diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..e704801 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,31 @@ +module.exports = { + parser: '@babel/eslint-parser', + parserOptions: { + ecmaVersion: 12, + sourceType: 'module', + requireConfigFile: false, + }, + ignorePatterns: ['homebridge-ui', 'node_modules', 'demo'], + plugins: ['@babel', 'prettier'], + extends: ['eslint:recommended', 'plugin:prettier/recommended'], + root: true, + env: { + es2021: true, + node: true, + }, + rules: { + quotes: ['error', 'single'], + 'comma-dangle': ['error', 'only-multiline'], + 'no-multiple-empty-lines': ['warn', { max: 1, maxEOF: 0 }], + 'eol-last': ['error', 'always'], + 'space-before-function-paren': ['error', { named: 'never' }], + 'prettier/prettier': [ + 'warn', + { + singleQuote: true, + arrowParens: 'always', + printWidth: 120, + }, + ], + }, +}; diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 04b9b35..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "env": { - "es6": true, - "node": true - }, - "extends": "eslint:recommended", - "parserOptions": { - "ecmaVersion": 8, - "sourceType": "module" - }, - "rules": { - "indent": [ - "error", - 2, - { - "SwitchCase": 1 - } - ], - "linebreak-style": [ - "error", - "unix" - ], - "quotes": [ - "error", - "single" - ], - "semi": [ - "error", - "always" - ], - "no-console": [ - "off" - ] - } -} diff --git a/.gitignore b/.gitignore index 8a0ff8c..e6806b2 100644 --- a/.gitignore +++ b/.gitignore @@ -55,19 +55,4 @@ typings/ .yarn-integrity # dotenv environment variables file -.env - -# next.js build output -.next -.github/ -images/ -demo/ -docs/ -example/ -CHANGELOG.md -CONTRIBUTING.md -FAQ.md -README.md -LICENSE -.eslintrc.json -example-config.json +.env \ No newline at end of file diff --git a/.npmignore b/.npmignore index 858542e..4ec369c 100644 --- a/.npmignore +++ b/.npmignore @@ -1,8 +1,64 @@ -.eslintrc.json -CHANGELOG.md -example-config.json -LICENSE -README.md -images -demo +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Optional npm cache directory +.npm +package-lock.json +yarn.lock + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.envtest/ .github +.vscode +demo +images +eslintrc.js +example-config.json +prettierrc.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..cb4c3d1 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "arrowParens": "always", + "printWidth": 120 +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1ab9283 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "git.ignoreLimitWarning": true, + "editor.tabSize": 2, + "editor.insertSpaces": true, + "files.eol": "\n", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + }, + "editor.formatOnSave": true, + "eslint.workingDirectories": ["./"] +} diff --git a/index.js b/index.js index c30f50f..1dd0e90 100644 --- a/index.js +++ b/index.js @@ -4,13 +4,11 @@ * @url https://github.com/SeydX/homebridge-tado-platform * @author SeydX * -**/ + **/ 'use strict'; module.exports = function (homebridge) { - let TadoPlatform = require('./src/platform.js')(homebridge); homebridge.registerPlatform('homebridge-tado-platform', 'TadoPlatform', TadoPlatform, true); - }; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..06d89a7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6009 @@ +{ + "name": "homebridge-tado-platform", + "version": "6.0.12", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "6.0.12", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/seydx" + }, + { + "type": "kofi", + "url": "https://ko-fi.com/seydx" + }, + { + "type": "github", + "url": "https://github.com/sponsors/seydx" + } + ], + "license": "MIT", + "dependencies": { + "@homebridge/plugin-ui-utils": "^0.0.19", + "fakegato-history": "^0.6.1", + "form-data": "^4.0.0", + "fs-extra": "^10.0.0", + "got": "^11.8.2", + "moment": "^2.29.1", + "simple-oauth2": "^4.2.0" + }, + "devDependencies": { + "@babel/core": "7.14.2", + "@babel/eslint-parser": "7.14.2", + "@babel/eslint-plugin": "7.13.16", + "eslint": "^7.26.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-import": "^2.23.2", + "eslint-plugin-prettier": "^3.4.0", + "prettier": "^2.3.0" + }, + "engines": { + "homebridge": "^1.1.6", + "node": ">=12.18.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.12.13" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.0.tgz", + "integrity": "sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q==", + "dev": true + }, + "node_modules/@babel/core": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.2.tgz", + "integrity": "sha512-OgC1mON+l4U4B4wiohJlQNUU3H73mpTyYY3j/c8U9dr9UagGGSm+WFpzjy/YLdoyjiG++c1kIDgxCo/mLwQJeQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.14.2", + "@babel/helper-compilation-targets": "^7.13.16", + "@babel/helper-module-transforms": "^7.14.2", + "@babel/helpers": "^7.14.0", + "@babel/parser": "^7.14.2", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.2", + "@babel/types": "^7.14.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.14.2.tgz", + "integrity": "sha512-g1YXHASb84MvEkReG/nZ74emTPAMjip1Ey6azZqKTEWidpgEzPGl/uoc6IPJjaMGw424u40sNm1V70tuYOQmeA==", + "dev": true, + "dependencies": { + "eslint-scope": "^5.1.0", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.11.0", + "eslint": ">=7.5.0" + } + }, + "node_modules/@babel/eslint-plugin": { + "version": "7.13.16", + "resolved": "https://registry.npmjs.org/@babel/eslint-plugin/-/eslint-plugin-7.13.16.tgz", + "integrity": "sha512-RNL0dLHBvjXW857JwzToTHxtbOZfGcvdSegcgXC1c1PqfE+o/QN8MugkgKj2vXFxCcMByfxJrmpCbLzVBVlgIA==", + "dev": true, + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/eslint-parser": ">=7.11.0", + "eslint": ">=7.5.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.2.tgz", + "integrity": "sha512-OnADYbKrffDVai5qcpkMxQ7caomHOoEwjkouqnN2QhydAjowFAZcsdecFIRUBdb+ZcruwYE4ythYmF1UBZU5xQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.14.2", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.13.16", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz", + "integrity": "sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.13.15", + "@babel/helper-validator-option": "^7.12.17", + "browserslist": "^4.14.5", + "semver": "^6.3.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz", + "integrity": "sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/types": "^7.14.2" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", + "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", + "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.13.12" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", + "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.13.12" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.2.tgz", + "integrity": "sha512-OznJUda/soKXv0XhpvzGWDnml4Qnwp16GN+D/kZIdLsWoHj05kyu8Rm5kXmMef+rVJZ0+4pSGLkeixdqNUATDA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.13.12", + "@babel/helper-replace-supers": "^7.13.12", + "@babel/helper-simple-access": "^7.13.12", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/helper-validator-identifier": "^7.14.0", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.2", + "@babel/types": "^7.14.2" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", + "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", + "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.13.12", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.12" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", + "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.13.12" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", + "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", + "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", + "dev": true + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", + "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", + "dev": true + }, + "node_modules/@babel/helpers": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.0.tgz", + "integrity": "sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.0", + "@babel/types": "^7.14.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", + "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.2.tgz", + "integrity": "sha512-IoVDIHpsgE/fu7eXBeRWt8zLbDrSvD7H1gpomOkPpBoEN8KCruCqSDdqo8dddwQQrui30KSvQBaMUOJiuFu6QQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", + "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.2.tgz", + "integrity": "sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.14.2", + "@babel/helper-function-name": "^7.14.2", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/parser": "^7.14.2", + "@babel/types": "^7.14.2", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "node_modules/@babel/types": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz", + "integrity": "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.0", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz", + "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==", + "dev": true, + "dependencies": { + "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", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@hapi/boom": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.2.tgz", + "integrity": "sha512-uJEJtiNHzKw80JpngDGBCGAmWjBtzxDCz17A9NO2zCi8LLBlb5Frpq4pXwyN+2JQMod4pKz5BALwyneCgDg89Q==", + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/bourne": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.0.0.tgz", + "integrity": "sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg==" + }, + "node_modules/@hapi/hoek": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", + "integrity": "sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug==" + }, + "node_modules/@hapi/topo": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz", + "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@hapi/wreck": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-17.1.0.tgz", + "integrity": "sha512-nx6sFyfqOpJ+EFrHX+XWwJAxs3ju4iHdbB/bwR8yTNZOiYmuhA8eCe7lYPtYmb4j7vyK/SlbaQsmTtUrMvPEBw==", + "dependencies": { + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@homebridge/plugin-ui-utils": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", + "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" + }, + "node_modules/@sideway/address": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", + "integrity": "sha512-idTz8ibqWFrPU8kMirL0CoPH/A29XOzzAzpyN3zQ4kAWnzmNfFmRaoMNN6VI8ske5M73HZyhIaW4OuSFIdM4oA==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "node_modules/@sindresorhus/is": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", + "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", + "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", + "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", + "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "node_modules/@types/keyv": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", + "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", + "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" + }, + "node_modules/@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==", + "engines": { + "node": "*" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", + "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001228", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz", + "integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/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, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/contains-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-1.0.0.tgz", + "integrity": "sha1-NFizMhhWA+ju0Y9RjUoQiIo6vJE=", + "dev": true, + "dependencies": { + "normalize-path": "^2.1.1", + "path-starts-with": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/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, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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 + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.3.728", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.728.tgz", + "integrity": "sha512-SHv4ziXruBpb1Nz4aTuqEHBYi/9GNCJMYIJgDEXrp/2V01nFXMNFUTli5Z85f5ivSkioLilQatqBYFB44wNJrA==", + "dev": true + }, + "node_modules/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 + }, + "node_modules/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==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/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, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/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, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", + "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz", + "integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.1", + "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.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^13.6.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.21", + "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": "^6.0.4", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", + "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.23.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.2.tgz", + "integrity": "sha512-LmNoRptHBxOP+nb0PIKz1y6OSzCJlB+0g0IGS3XV4KaKk2q4szqQ6s6F1utVf5ZRkxk/QOTjdxe7v4VjS99Bsg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "contains-path": "^1.0.0", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-plugin-prettier": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", + "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=5.0.0", + "prettier": ">=1.13.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/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, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/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 + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz", + "integrity": "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/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, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/fakegato-history": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.6.1.tgz", + "integrity": "sha512-RcgxQj8LEnO/Bt1fxT3pbeLPmDlZ7hZKiW6CPvTGgOHfKYUktXAVKhzj7/Nq14MRWx6DYO+BoI4zZCQDgkob/A==", + "dependencies": { + "debug": "^2.2.0", + "googleapis": ">39.1.0" + }, + "engines": { + "homebridge": ">=0.4.0", + "node": ">=4.3.2" + } + }, + "node_modules/fakegato-history/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/fakegato-history/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/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 + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/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 + }, + "node_modules/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 + }, + "node_modules/fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/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 + }, + "node_modules/gaxios": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.2.1.tgz", + "integrity": "sha512-s+rTywpw6CmfB8r9TXYkpix7YFeuRjnR/AqhaJrQqsNhsAqej+IAiCc3hadzQH3gHyWth30tvYjxH8EVjQt/8Q==", + "dependencies": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gcp-metadata": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.1.tgz", + "integrity": "sha512-tSk+REe5iq/N+K+SK1XjZJUrFPuDqGZVzCy2vocIHIGmPlTGsa8owXMJwGkrXr73NO0AzhPW4MF2DEHz7P2AVw==", + "dependencies": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/google-auth-library": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.0.4.tgz", + "integrity": "sha512-o8irYyeijEiecTXeoEe8UKNEzV1X+uhR4b2oNdapDMZixypp0J+eHimGOyx5Joa3UAeokGngdtDLXtq9vDqG2Q==", + "dependencies": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-p12-pem": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", + "dependencies": { + "node-forge": "^0.10.0" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/googleapis": { + "version": "73.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-73.0.0.tgz", + "integrity": "sha512-bLLoHddONoEZCnhcTW603r7Y1fFqbFo0/3VdnzTNA4XQl+gVY3qycWmRSRrL15ts9Iwfg0rhTde5+OUuBFhi0g==", + "dependencies": { + "google-auth-library": "^7.0.2", + "googleapis-common": "^5.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/googleapis-common": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-5.0.2.tgz", + "integrity": "sha512-TL7qronKNZwE/XBvqshwzCPmZGq2gz/beXzANF7EVoO7FsQjOd7dk40DYrXkoCpvbnJHCQKWESq6NansiIPFqA==", + "dependencies": { + "extend": "^3.0.2", + "gaxios": "^4.0.0", + "google-auth-library": "^7.0.2", + "qs": "^6.7.0", + "url-template": "^2.0.8", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/got": { + "version": "11.8.2", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.2.tgz", + "integrity": "sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.1", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "node_modules/gtoken": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.2.1.tgz", + "integrity": "sha512-OY0BfPKe3QnMsY9MzTHTSKn+Vl2l1CcLe6BwDEQj00mbbkl5nyQ/7EUREstg4fQNZ8iYE7br4JJ7TdKeDOPWmw==", + "dependencies": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/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, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/joi": { + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.4.0.tgz", + "integrity": "sha512-F4WiW2xaV6wc1jxete70Rw4V/VuMd6IN+a5ilZsxG4uYtUXWu2kq9W5P2dz30e7Gmw8RCbY/u/uk+dMPma9tAg==", + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.0", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/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 + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keyv": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.3.tgz", + "integrity": "sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/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, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/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, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mime-db": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "dependencies": { + "mime-db": "1.47.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/node-releases": { + "version": "1.1.72", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", + "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/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, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", + "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/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 + }, + "node_modules/path-starts-with": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-starts-with/-/path-starts-with-1.0.0.tgz", + "integrity": "sha1-soJDAV6LE43lcmgqxS2kLmRq2E4=", + "dev": true, + "dependencies": { + "normalize-path": "^2.1.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz", + "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/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, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/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, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.1.2.tgz", + "integrity": "sha512-8OyfzhAtA32LVUsJSke3auIyINcwdh5l3cvYKdKO0nvsYSKuiLfTM5i78PJswFPT8y6cPW+L1v6/hE95chcpDA==" + }, + "node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/responselike": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "dependencies": { + "lowercase-keys": "^2.0.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/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, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-oauth2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/simple-oauth2/-/simple-oauth2-4.2.0.tgz", + "integrity": "sha512-AV62tGdq9JfLd/uveKpeNtQl+VVm89a35QKlwGuvisYIjCoz2ZmTGRGuSIGiYr+QUhSKJ5kYN1jq2BBa/ac/GQ==", + "dependencies": { + "@hapi/hoek": "^9.0.4", + "@hapi/wreck": "^17.0.0", + "debug": "^4.1.1", + "joi": "^17.3.0" + } + }, + "node_modules/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, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/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 + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "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, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.4.0.tgz", + "integrity": "sha512-7QD2l6+KBSLwf+7MuYocbWvRPdOu63/trReTLu2KFwkgctnub1auoF+Y1WYcm09CTM7quuscrzqmASaLHC/K4Q==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/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 + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.12.13" + } + }, + "@babel/compat-data": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.0.tgz", + "integrity": "sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q==", + "dev": true + }, + "@babel/core": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.2.tgz", + "integrity": "sha512-OgC1mON+l4U4B4wiohJlQNUU3H73mpTyYY3j/c8U9dr9UagGGSm+WFpzjy/YLdoyjiG++c1kIDgxCo/mLwQJeQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.14.2", + "@babel/helper-compilation-targets": "^7.13.16", + "@babel/helper-module-transforms": "^7.14.2", + "@babel/helpers": "^7.14.0", + "@babel/parser": "^7.14.2", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.2", + "@babel/types": "^7.14.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + } + }, + "@babel/eslint-parser": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.14.2.tgz", + "integrity": "sha512-g1YXHASb84MvEkReG/nZ74emTPAMjip1Ey6azZqKTEWidpgEzPGl/uoc6IPJjaMGw424u40sNm1V70tuYOQmeA==", + "dev": true, + "requires": { + "eslint-scope": "^5.1.0", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.0" + } + }, + "@babel/eslint-plugin": { + "version": "7.13.16", + "resolved": "https://registry.npmjs.org/@babel/eslint-plugin/-/eslint-plugin-7.13.16.tgz", + "integrity": "sha512-RNL0dLHBvjXW857JwzToTHxtbOZfGcvdSegcgXC1c1PqfE+o/QN8MugkgKj2vXFxCcMByfxJrmpCbLzVBVlgIA==", + "dev": true, + "requires": { + "eslint-rule-composer": "^0.3.0" + } + }, + "@babel/generator": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.2.tgz", + "integrity": "sha512-OnADYbKrffDVai5qcpkMxQ7caomHOoEwjkouqnN2QhydAjowFAZcsdecFIRUBdb+ZcruwYE4ythYmF1UBZU5xQ==", + "dev": true, + "requires": { + "@babel/types": "^7.14.2", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.13.16", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz", + "integrity": "sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.15", + "@babel/helper-validator-option": "^7.12.17", + "browserslist": "^4.14.5", + "semver": "^6.3.0" + } + }, + "@babel/helper-function-name": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz", + "integrity": "sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/types": "^7.14.2" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", + "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", + "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", + "dev": true, + "requires": { + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-module-imports": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", + "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", + "dev": true, + "requires": { + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-module-transforms": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.2.tgz", + "integrity": "sha512-OznJUda/soKXv0XhpvzGWDnml4Qnwp16GN+D/kZIdLsWoHj05kyu8Rm5kXmMef+rVJZ0+4pSGLkeixdqNUATDA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.13.12", + "@babel/helper-replace-supers": "^7.13.12", + "@babel/helper-simple-access": "^7.13.12", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/helper-validator-identifier": "^7.14.0", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.2", + "@babel/types": "^7.14.2" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", + "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-replace-supers": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", + "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.13.12", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-simple-access": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", + "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", + "dev": true, + "requires": { + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", + "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", + "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", + "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.0.tgz", + "integrity": "sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg==", + "dev": true, + "requires": { + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.0", + "@babel/types": "^7.14.0" + } + }, + "@babel/highlight": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", + "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.2.tgz", + "integrity": "sha512-IoVDIHpsgE/fu7eXBeRWt8zLbDrSvD7H1gpomOkPpBoEN8KCruCqSDdqo8dddwQQrui30KSvQBaMUOJiuFu6QQ==", + "dev": true + }, + "@babel/template": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", + "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "@babel/traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.2.tgz", + "integrity": "sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.14.2", + "@babel/helper-function-name": "^7.14.2", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/parser": "^7.14.2", + "@babel/types": "^7.14.2", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz", + "integrity": "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.0", + "to-fast-properties": "^2.0.0" + } + }, + "@eslint/eslintrc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz", + "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "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" + } + } + } + }, + "@hapi/boom": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.2.tgz", + "integrity": "sha512-uJEJtiNHzKw80JpngDGBCGAmWjBtzxDCz17A9NO2zCi8LLBlb5Frpq4pXwyN+2JQMod4pKz5BALwyneCgDg89Q==", + "requires": { + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/bourne": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.0.0.tgz", + "integrity": "sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg==" + }, + "@hapi/hoek": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", + "integrity": "sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug==" + }, + "@hapi/topo": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz", + "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@hapi/wreck": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-17.1.0.tgz", + "integrity": "sha512-nx6sFyfqOpJ+EFrHX+XWwJAxs3ju4iHdbB/bwR8yTNZOiYmuhA8eCe7lYPtYmb4j7vyK/SlbaQsmTtUrMvPEBw==", + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "@homebridge/plugin-ui-utils": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", + "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" + }, + "@sideway/address": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", + "integrity": "sha512-idTz8ibqWFrPU8kMirL0CoPH/A29XOzzAzpyN3zQ4kAWnzmNfFmRaoMNN6VI8ske5M73HZyhIaW4OuSFIdM4oA==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "@sindresorhus/is": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", + "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==" + }, + "@szmarczak/http-timer": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", + "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "@types/cacheable-request": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", + "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", + "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==" + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/keyv": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", + "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", + "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" + }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "requires": { + "@types/node": "*" + } + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "requires": {} + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "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" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-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": "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" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + } + }, + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "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 + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==" + }, + "cacheable-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", + "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^2.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001228", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz", + "integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==", + "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==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.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 + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "contains-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-1.0.0.tgz", + "integrity": "sha1-NFizMhhWA+ju0Y9RjUoQiIo6vJE=", + "dev": true, + "requires": { + "normalize-path": "^2.1.1", + "path-starts-with": "^1.0.0" + } + }, + "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" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } + } + }, + "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 + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "electron-to-chromium": { + "version": "1.3.728", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.728.tgz", + "integrity": "sha512-SHv4ziXruBpb1Nz4aTuqEHBYi/9GNCJMYIJgDEXrp/2V01nFXMNFUTli5Z85f5ivSkioLilQatqBYFB44wNJrA==", + "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 + }, + "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==", + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", + "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "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=", + "dev": true + }, + "eslint": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz", + "integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.1", + "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.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^13.6.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.21", + "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": "^6.0.4", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "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 + }, + "globals": { + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz", + "integrity": "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "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 + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "requires": {} + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", + "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.23.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.2.tgz", + "integrity": "sha512-LmNoRptHBxOP+nb0PIKz1y6OSzCJlB+0g0IGS3XV4KaKk2q4szqQ6s6F1utVf5ZRkxk/QOTjdxe7v4VjS99Bsg==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "contains-path": "^1.0.0", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.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" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-prettier": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", + "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.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.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fakegato-history": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.6.1.tgz", + "integrity": "sha512-RcgxQj8LEnO/Bt1fxT3pbeLPmDlZ7hZKiW6CPvTGgOHfKYUktXAVKhzj7/Nq14MRWx6DYO+BoI4zZCQDgkob/A==", + "requires": { + "debug": "^2.2.0", + "googleapis": ">39.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "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 + }, + "fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "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" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "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 + }, + "gaxios": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.2.1.tgz", + "integrity": "sha512-s+rTywpw6CmfB8r9TXYkpix7YFeuRjnR/AqhaJrQqsNhsAqej+IAiCc3hadzQH3gHyWth30tvYjxH8EVjQt/8Q==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.1.tgz", + "integrity": "sha512-tSk+REe5iq/N+K+SK1XjZJUrFPuDqGZVzCy2vocIHIGmPlTGsa8owXMJwGkrXr73NO0AzhPW4MF2DEHz7P2AVw==", + "requires": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "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==", + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "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": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "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 + }, + "google-auth-library": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.0.4.tgz", + "integrity": "sha512-o8irYyeijEiecTXeoEe8UKNEzV1X+uhR4b2oNdapDMZixypp0J+eHimGOyx5Joa3UAeokGngdtDLXtq9vDqG2Q==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "googleapis": { + "version": "73.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-73.0.0.tgz", + "integrity": "sha512-bLLoHddONoEZCnhcTW603r7Y1fFqbFo0/3VdnzTNA4XQl+gVY3qycWmRSRrL15ts9Iwfg0rhTde5+OUuBFhi0g==", + "requires": { + "google-auth-library": "^7.0.2", + "googleapis-common": "^5.0.2" + } + }, + "googleapis-common": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-5.0.2.tgz", + "integrity": "sha512-TL7qronKNZwE/XBvqshwzCPmZGq2gz/beXzANF7EVoO7FsQjOd7dk40DYrXkoCpvbnJHCQKWESq6NansiIPFqA==", + "requires": { + "extend": "^3.0.2", + "gaxios": "^4.0.0", + "google-auth-library": "^7.0.2", + "qs": "^6.7.0", + "url-template": "^2.0.8", + "uuid": "^8.0.0" + } + }, + "got": { + "version": "11.8.2", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.2.tgz", + "integrity": "sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==", + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.1", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "gtoken": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.2.1.tgz", + "integrity": "sha512-OY0BfPKe3QnMsY9MzTHTSKn+Vl2l1CcLe6BwDEQj00mbbkl5nyQ/7EUREstg4fQNZ8iYE7br4JJ7TdKeDOPWmw==", + "requires": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "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 + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", + "dev": true + }, + "is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "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 + }, + "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-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, + "is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", + "dev": true + }, + "is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "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==" + }, + "is-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", + "dev": true + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "joi": { + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.4.0.tgz", + "integrity": "sha512-F4WiW2xaV6wc1jxete70Rw4V/VuMd6IN+a5ilZsxG4uYtUXWu2kq9W5P2dz30e7Gmw8RCbY/u/uk+dMPma9tAg==", + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.0", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.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.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "keyv": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.3.tgz", + "integrity": "sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==", + "requires": { + "json-buffer": "3.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "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" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "mime-db": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==" + }, + "mime-types": { + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "requires": { + "mime-db": "1.47.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "node-releases": { + "version": "1.1.72", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", + "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "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" + } + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" + }, + "object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.values": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", + "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" + }, + "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 + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "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-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "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 + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-starts-with": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-starts-with/-/path-starts-with-1.0.0.tgz", + "integrity": "sha1-soJDAV6LE43lcmgqxS2kLmRq2E4=", + "dev": true, + "requires": { + "normalize-path": "^2.1.1" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz", + "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" + }, + "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" + }, + "dependencies": { + "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-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" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-alpn": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.1.2.tgz", + "integrity": "sha512-8OyfzhAtA32LVUsJSke3auIyINcwdh5l3cvYKdKO0nvsYSKuiLfTM5i78PJswFPT8y6cPW+L1v6/hE95chcpDA==" + }, + "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 + }, + "responselike": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "requires": { + "lowercase-keys": "^2.0.0" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "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 + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "simple-oauth2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/simple-oauth2/-/simple-oauth2-4.2.0.tgz", + "integrity": "sha512-AV62tGdq9JfLd/uveKpeNtQl+VVm89a35QKlwGuvisYIjCoz2ZmTGRGuSIGiYr+QUhSKJ5kYN1jq2BBa/ac/GQ==", + "requires": { + "@hapi/hoek": "^9.0.4", + "@hapi/wreck": "^17.0.0", + "debug": "^4.1.1", + "joi": "^17.3.0" + } + }, + "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" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "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 + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "spdx-correct": { + "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", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.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", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.4.0.tgz", + "integrity": "sha512-7QD2l6+KBSLwf+7MuYocbWvRPdOu63/trReTLu2KFwkgctnub1auoF+Y1WYcm09CTM7quuscrzqmASaLHC/K4Q==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "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 + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "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" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/package.json b/package.json index b7f4fc9..4807bd3 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "version": "6.0.12", "description": "homebridge-tado-platform", "main": "index.js", - "devDependencies": {}, "funding": [ { "type": "paypal", @@ -19,7 +18,7 @@ } ], "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "lint": "eslint --fix ." }, "repository": { "type": "git", @@ -49,9 +48,19 @@ "@homebridge/plugin-ui-utils": "^0.0.19", "fakegato-history": "^0.6.1", "form-data": "^4.0.0", - "fs-extra": "^9.1.0", + "fs-extra": "^10.0.0", "got": "^11.8.2", "moment": "^2.29.1", "simple-oauth2": "^4.2.0" + }, + "devDependencies": { + "@babel/core": "7.14.2", + "@babel/eslint-parser": "7.14.2", + "@babel/eslint-plugin": "7.13.16", + "eslint": "^7.26.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-import": "^2.23.2", + "eslint-plugin-prettier": "^3.4.0", + "prettier": "^2.3.0" } } diff --git a/src/accessories/airquality.js b/src/accessories/airquality.js index e757a82..968c0b7 100644 --- a/src/accessories/airquality.js +++ b/src/accessories/airquality.js @@ -3,57 +3,54 @@ const Logger = require('../helper/logger.js'); class AirQualityAccessory { - - constructor (api, accessory, accessories, tado) { - + constructor(api, accessory, accessories, tado) { this.api = api; this.accessory = accessory; this.accessories = accessories; - + this.tado = tado; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - getService () { - + getService() { let service = this.accessory.getService(this.api.hap.Service.AirQualitySensor); - - if(!service){ + + if (!service) { Logger.info('Adding AirQualitySensor service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.AirQualitySensor, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.AirQualitySensor, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - + if (!service.testCharacteristic(this.api.hap.Characteristic.PM10Density)) service.addCharacteristic(this.api.hap.Characteristic.PM10Density); - + if (!service.testCharacteristic(this.api.hap.Characteristic.PM2_5Density)) service.addCharacteristic(this.api.hap.Characteristic.PM2_5Density); - + if (!service.testCharacteristic(this.api.hap.Characteristic.NitrogenDioxideDensity)) service.addCharacteristic(this.api.hap.Characteristic.NitrogenDioxideDensity); - + if (!service.testCharacteristic(this.api.hap.Characteristic.OzoneDensity)) service.addCharacteristic(this.api.hap.Characteristic.OzoneDensity); - + if (!service.testCharacteristic(this.api.hap.Characteristic.SulphurDioxideDensity)) service.addCharacteristic(this.api.hap.Characteristic.SulphurDioxideDensity); - + if (!service.testCharacteristic(this.api.hap.Characteristic.CarbonMonoxideLevel)) service.addCharacteristic(this.api.hap.Characteristic.CarbonMonoxideLevel); - - service.getCharacteristic(this.api.hap.Characteristic.CarbonMonoxideLevel) - .setProps({ - minStep: 0.01 - }); - - } + service.getCharacteristic(this.api.hap.Characteristic.CarbonMonoxideLevel).setProps({ + minStep: 0.01, + }); + } } -module.exports = AirQualityAccessory; \ No newline at end of file +module.exports = AirQualityAccessory; diff --git a/src/accessories/contact.js b/src/accessories/contact.js index 64b73a2..0710181 100644 --- a/src/accessories/contact.js +++ b/src/accessories/contact.js @@ -7,115 +7,118 @@ const moment = require('moment'); const timeout = (ms) => new Promise((res) => setTimeout(res, ms)); class ContactAccessory { - - constructor (api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { - + constructor(api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { this.api = api; this.accessory = accessory; this.accessories = accessories; this.FakeGatoHistoryService = FakeGatoHistoryService; - + this.deviceHandler = deviceHandler; this.tado = tado; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - async getService () { - + async getService() { let service = this.accessory.getService(this.api.hap.Service.ContactSensor); let serviceSwitch = this.accessory.getService(this.api.hap.Service.Switch); - - if(serviceSwitch){ + + if (serviceSwitch) { Logger.info('Removing Switch service', this.accessory.displayName); this.accessory.removeService(serviceSwitch); } - if(!service){ + if (!service) { Logger.info('Adding ContactSensor service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.ContactSensor, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.ContactSensor, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - + let batteryService = this.accessory.getService(this.api.hap.Service.BatteryService); - - if(!this.accessory.context.config.noBattery && this.accessory.context.config.type === 'HEATING'){ - if(!batteryService){ + + if (!this.accessory.context.config.noBattery && this.accessory.context.config.type === 'HEATING') { + if (!batteryService) { Logger.info('Adding Battery service', this.accessory.displayName); batteryService = this.accessory.addService(this.api.hap.Service.BatteryService); } - batteryService - .setCharacteristic(this.api.hap.Characteristic.ChargingState, this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE); + batteryService.setCharacteristic( + this.api.hap.Characteristic.ChargingState, + this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE + ); } else { - if(batteryService){ + if (batteryService) { Logger.info('Removing Battery service', this.accessory.displayName); this.accessory.removeService(batteryService); } } - + if (!service.testCharacteristic(this.api.hap.Characteristic.LastActivation)) service.addCharacteristic(this.api.hap.Characteristic.LastActivation); - + if (!service.testCharacteristic(this.api.hap.Characteristic.TimesOpened)) service.addCharacteristic(this.api.hap.Characteristic.TimesOpened); if (!service.testCharacteristic(this.api.hap.Characteristic.ResetTotal)) - service.addCharacteristic(this.api.hap.Characteristic.ResetTotal); - + service.addCharacteristic(this.api.hap.Characteristic.ResetTotal); + if (!service.testCharacteristic(this.api.hap.Characteristic.OpenDuration)) service.addCharacteristic(this.api.hap.Characteristic.OpenDuration); - + if (!service.testCharacteristic(this.api.hap.Characteristic.ClosedDuration)) service.addCharacteristic(this.api.hap.Characteristic.ClosedDuration); - - service.getCharacteristic(this.api.hap.Characteristic.ResetTotal) - .onSet(value => { - - Logger.info(value + ': Resetting FakeGato..', this.accessory.displayName); - - const now = Math.round(new Date().valueOf() / 1000); - const epoch = Math.round(new Date('2001-01-01T00:00:00Z').valueOf() / 1000); - - service.getCharacteristic(this.api.hap.Characteristic.ResetTotal) - .updateValue(now - epoch); - - this.accessory.context.timesOpened = 0; - - service.getCharacteristic(this.api.hap.Characteristic.TimesOpened) - .updateValue(this.accessory.context.timesOpened); - - }); - - this.historyService = new this.FakeGatoHistoryService('door', this.accessory, {storage:'fs', path: this.api.user.storagePath(), disableTimer:true}); - + + service.getCharacteristic(this.api.hap.Characteristic.ResetTotal).onSet((value) => { + Logger.info(value + ': Resetting FakeGato..', this.accessory.displayName); + + const now = Math.round(new Date().valueOf() / 1000); + const epoch = Math.round(new Date('2001-01-01T00:00:00Z').valueOf() / 1000); + + service.getCharacteristic(this.api.hap.Characteristic.ResetTotal).updateValue(now - epoch); + + this.accessory.context.timesOpened = 0; + + service + .getCharacteristic(this.api.hap.Characteristic.TimesOpened) + .updateValue(this.accessory.context.timesOpened); + }); + + this.historyService = new this.FakeGatoHistoryService('door', this.accessory, { + storage: 'fs', + path: this.api.user.storagePath(), + disableTimer: true, + }); + await timeout(250); //wait for historyService to load - - service.getCharacteristic(this.api.hap.Characteristic.ContactSensorState) - .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)); - + + service + .getCharacteristic(this.api.hap.Characteristic.ContactSensorState) + .on( + 'change', + this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName) + ); + this.refreshHistory(service); - } - - refreshHistory(service){ - + + refreshHistory(service) { let state = service.getCharacteristic(this.api.hap.Characteristic.ContactSensorState).value; - + this.historyService.addEntry({ - time: moment().unix(), - status: state ? 1 : 0 + time: moment().unix(), + status: state ? 1 : 0, }); - + setTimeout(() => { this.refreshHistory(service); }, 10 * 60 * 1000); - } - } -module.exports = ContactAccessory; \ No newline at end of file +module.exports = ContactAccessory; diff --git a/src/accessories/faucet.js b/src/accessories/faucet.js index e4c91ad..4a72bcb 100644 --- a/src/accessories/faucet.js +++ b/src/accessories/faucet.js @@ -3,64 +3,61 @@ const Logger = require('../helper/logger.js'); class FaucetAccessory { - - constructor (api, accessory, accessories, tado, deviceHandler) { - + constructor(api, accessory, accessories, tado, deviceHandler) { this.api = api; this.accessory = accessory; this.accessories = accessories; - + this.deviceHandler = deviceHandler; this.tado = tado; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - getService () { - + getService() { let service = this.accessory.getService(this.api.hap.Service.Valve); let serviceSwitch = this.accessory.getService(this.api.hap.Service.Switch); let serviceHeaterCooler = this.accessory.getService(this.api.hap.Service.HeaterCooler); let serviceThermostat = this.accessory.getService(this.api.hap.Service.Thermostat); - - if(serviceSwitch){ + + if (serviceSwitch) { Logger.info('Removing Switch service', this.accessory.displayName); this.accessory.removeService(serviceSwitch); } - - if(serviceThermostat){ + + if (serviceThermostat) { Logger.info('Removing Thermostat service', this.accessory.displayName); this.accessory.removeService(serviceThermostat); } - - if(serviceHeaterCooler){ + + if (serviceHeaterCooler) { Logger.info('Removing HeaterCooler service', this.accessory.displayName); this.accessory.removeService(serviceHeaterCooler); } - - if(!service){ + + if (!service) { Logger.info('Adding Faucet service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.Valve, this.accessory.displayName, this.accessory.context.config.subtype); - + service = this.accessory.addService( + this.api.hap.Service.Valve, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - + service .setCharacteristic(this.api.hap.Characteristic.Name, this.accessory.displayName) .setCharacteristic(this.api.hap.Characteristic.IsConfigured, this.api.hap.Characteristic.IsConfigured.CONFIGURED) .setCharacteristic(this.api.hap.Characteristic.StatusFault, this.api.hap.Characteristic.StatusFault.NO_FAULT) .setCharacteristic(this.api.hap.Characteristic.ValveType, this.api.hap.Characteristic.ValveType.WATER_FAUCET); - - service.getCharacteristic(this.api.hap.Characteristic.Active) - .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, 'State')) ; - - - } + service + .getCharacteristic(this.api.hap.Characteristic.Active) + .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, 'State')); + } } -module.exports = FaucetAccessory; \ No newline at end of file +module.exports = FaucetAccessory; diff --git a/src/accessories/heatercooler.js b/src/accessories/heatercooler.js index 886f896..a2856f9 100644 --- a/src/accessories/heatercooler.js +++ b/src/accessories/heatercooler.js @@ -7,342 +7,327 @@ const moment = require('moment'); const timeout = (ms) => new Promise((res) => setTimeout(res, ms)); class HeaterCoolerAccessory { - - constructor (api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { - + constructor(api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { this.api = api; this.accessory = accessory; - this.accessories = accessories; + this.accessories = accessories; this.FakeGatoHistoryService = FakeGatoHistoryService; - + this.deviceHandler = deviceHandler; this.tado = tado; - + this.autoDelayTimeout = null; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - async getService () { - + async getService() { let service = this.accessory.getService(this.api.hap.Service.HeaterCooler); let serviceThermostat = this.accessory.getService(this.api.hap.Service.Thermostat); let serviceSwitch = this.accessory.getService(this.api.hap.Service.Switch); let serviceFaucet = this.accessory.getService(this.api.hap.Service.Valve); - - if(serviceThermostat){ + + if (serviceThermostat) { Logger.info('Removing Thermostat service', this.accessory.displayName); this.accessory.removeService(serviceThermostat); } - - if(serviceSwitch){ + + if (serviceSwitch) { Logger.info('Removing Switch service', this.accessory.displayName); this.accessory.removeService(serviceSwitch); } - - if(serviceFaucet){ + + if (serviceFaucet) { Logger.info('Removing Faucet service', this.accessory.displayName); this.accessory.removeService(serviceFaucet); } - - if(!service){ + + if (!service) { Logger.info('Adding HeaterCooler service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.HeaterCooler, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.HeaterCooler, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - + let batteryService = this.accessory.getService(this.api.hap.Service.BatteryService); - - if(!this.accessory.context.config.noBattery && this.accessory.context.config.type === 'HEATING'){ - if(!batteryService){ + + if (!this.accessory.context.config.noBattery && this.accessory.context.config.type === 'HEATING') { + if (!batteryService) { Logger.info('Adding Battery service', this.accessory.displayName); batteryService = this.accessory.addService(this.api.hap.Service.BatteryService); } - batteryService - .setCharacteristic(this.api.hap.Characteristic.ChargingState, this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE); + batteryService.setCharacteristic( + this.api.hap.Characteristic.ChargingState, + this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE + ); } else { - if(batteryService){ + if (batteryService) { Logger.info('Removing Battery service', this.accessory.displayName); this.accessory.removeService(batteryService); } } - + //Handle AirQuality - if(this.accessory.context.config.airQuality && this.accessory.context.config.type !== 'HOT_WATER'){ - - if(!service.testCharacteristic(this.api.hap.Characteristic.AirQuality)) + if (this.accessory.context.config.airQuality && this.accessory.context.config.type !== 'HOT_WATER') { + if (!service.testCharacteristic(this.api.hap.Characteristic.AirQuality)) service.addCharacteristic(this.api.hap.Characteristic.AirQuality); - } else { - - if(service.testCharacteristic(this.api.hap.Characteristic.AirQuality)) + if (service.testCharacteristic(this.api.hap.Characteristic.AirQuality)) service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.AirQuality)); - } - + //Handle DelaySwitch - if(this.accessory.context.config.delaySwitch && this.accessory.context.config.type !== 'HOT_WATER'){ - - if(!service.testCharacteristic(this.api.hap.Characteristic.DelaySwitch)) + if (this.accessory.context.config.delaySwitch && this.accessory.context.config.type !== 'HOT_WATER') { + if (!service.testCharacteristic(this.api.hap.Characteristic.DelaySwitch)) service.addCharacteristic(this.api.hap.Characteristic.DelaySwitch); - - if(!service.testCharacteristic(this.api.hap.Characteristic.DelayTimer)) + + if (!service.testCharacteristic(this.api.hap.Characteristic.DelayTimer)) service.addCharacteristic(this.api.hap.Characteristic.DelayTimer); - - if(this.accessory.context.config.autoOffDelay){ - - service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch) - .onSet(value => { - if(value && this.accessory.context.delayTimer){ + + if (this.accessory.context.config.autoOffDelay) { + service + .getCharacteristic(this.api.hap.Characteristic.DelaySwitch) + .onSet((value) => { + if (value && this.accessory.context.delayTimer) { this.autoDelayTimeout = setTimeout(() => { Logger.info('Timer expired, turning off delay switch', this.accessory.displayName); - service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch) - .updateValue(false); + service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch).updateValue(false); this.autoDelayTimeout = null; }, this.accessory.context.delayTimer * 1000); } else { - if(this.autoDelayTimeout){ + if (this.autoDelayTimeout) { clearTimeout(this.autoDelayTimeout); this.autoDelayTimeout = null; } - } + } }) .updateValue(false); - } else { - - service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch) + service + .getCharacteristic(this.api.hap.Characteristic.DelaySwitch) .onGet(() => { return this.accessory.context.delaySwitch || false; }) - .onSet(value => { + .onSet((value) => { this.accessory.context.delaySwitch = value; }); - } - - service.getCharacteristic(this.api.hap.Characteristic.DelayTimer) + + service + .getCharacteristic(this.api.hap.Characteristic.DelayTimer) .onGet(() => { return this.accessory.context.delayTimer || 0; }) - .onSet(value => { + .onSet((value) => { this.accessory.context.delayTimer = value; }); - - } else { - - if(service.testCharacteristic(this.api.hap.Characteristic.DelaySwitch)) + if (service.testCharacteristic(this.api.hap.Characteristic.DelaySwitch)) service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch)); - - if(service.testCharacteristic(this.api.hap.Characteristic.DelayTimer)) + + if (service.testCharacteristic(this.api.hap.Characteristic.DelayTimer)) service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.DelayTimer)); - } - + if (!service.testCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature)) service.addCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature); - - if (this.accessory.context.config.type === 'HEATING'){ - - if(!service.testCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature)) + + if (this.accessory.context.config.type === 'HEATING') { + if (!service.testCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature)) service.addCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature); - - if (!this.accessory.context.config.separateHumidity){ - if(!service.testCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity)) - service.addCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity); + + if (!this.accessory.context.config.separateHumidity) { + if (!service.testCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity)) + service.addCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity); } else { - if(service.testCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity)) + if (service.testCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity)) service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity)); } - } else { - - if(service.testCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature)) - service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature)); - + if (service.testCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature)) + service.removeCharacteristic( + service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature) + ); } - - let minValue = this.accessory.context.config.type === 'HOT_WATER' - ? this.accessory.context.config.temperatureUnit === 'CELSIUS' - ? 30 - : 86 - : this.accessory.context.config.temperatureUnit === 'CELSIUS' + + let minValue = + this.accessory.context.config.type === 'HOT_WATER' + ? this.accessory.context.config.temperatureUnit === 'CELSIUS' + ? 30 + : 86 + : this.accessory.context.config.temperatureUnit === 'CELSIUS' ? 5 : 41; - - let maxValue = this.accessory.context.config.type === 'HOT_WATER' - ? this.accessory.context.config.temperatureUnit === 'CELSIUS' - ? 65 - : 149 - : this.accessory.context.config.temperatureUnit === 'CELSIUS' + + let maxValue = + this.accessory.context.config.type === 'HOT_WATER' + ? this.accessory.context.config.temperatureUnit === 'CELSIUS' + ? 65 + : 149 + : this.accessory.context.config.temperatureUnit === 'CELSIUS' ? 25 : 77; - - minValue = this.accessory.context.config.minValue < maxValue - ? this.accessory.context.config.minValue - : minValue; - - maxValue = this.accessory.context.config.maxValue > minValue - ? this.accessory.context.config.maxValue - : maxValue; - + + minValue = this.accessory.context.config.minValue < maxValue ? this.accessory.context.config.minValue : minValue; + + maxValue = this.accessory.context.config.maxValue > minValue ? this.accessory.context.config.maxValue : maxValue; + console.log('Before MINSTEP: ' + this.accessory.context.config.minStep, this.accessory.displayName); - - let minStep = parseFloat((this.accessory.context.config.minStep && !isNaN(this.accessory.context.config.minStep) && this.accessory.context.config.minStep > 0 && this.accessory.context.config.minStep <= 1 - ? parseFloat(this.accessory.context.config.minStep) - : 1).toFixed(2)); - + + let minStep = parseFloat( + (this.accessory.context.config.minStep && + !isNaN(this.accessory.context.config.minStep) && + this.accessory.context.config.minStep > 0 && + this.accessory.context.config.minStep <= 1 + ? parseFloat(this.accessory.context.config.minStep) + : 1 + ).toFixed(2) + ); + console.log('After MINSTEP: ' + minStep, this.accessory.displayName); - - let maxState = this.accessory.context.config.type === 'HOT_WATER' - ? 2 - : 3; - - let validState = this.accessory.context.config.type === 'HOT_WATER' - ? [0, 1, 2] - : [0, 1, 2, 3]; - - if(service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState).value > maxState) - service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState) - .updateValue(maxState); - - service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState) - .setProps({ - maxValue: maxState, - minValue: 0, - validValues: validState - }); - - service.getCharacteristic(this.api.hap.Characteristic.TargetHeaterCoolerState) - .updateValue(1); - - service.getCharacteristic(this.api.hap.Characteristic.TargetHeaterCoolerState) - .setProps({ - maxValue: 1, - minValue: 1, - validValues: [1] - }); - - service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature) - .setProps({ - minValue: -255, - maxValue: 255 - }); - + + let maxState = this.accessory.context.config.type === 'HOT_WATER' ? 2 : 3; + + let validState = this.accessory.context.config.type === 'HOT_WATER' ? [0, 1, 2] : [0, 1, 2, 3]; + + if (service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState).value > maxState) + service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState).updateValue(maxState); + + service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState).setProps({ + maxValue: maxState, + minValue: 0, + validValues: validState, + }); + + service.getCharacteristic(this.api.hap.Characteristic.TargetHeaterCoolerState).updateValue(1); + + service.getCharacteristic(this.api.hap.Characteristic.TargetHeaterCoolerState).setProps({ + maxValue: 1, + minValue: 1, + validValues: [1], + }); + + service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature).setProps({ + minValue: -255, + maxValue: 255, + }); + if (service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).value < minValue) - service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature) - .updateValue(minValue); - + service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).updateValue(minValue); + if (service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).value > maxValue) - service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature) - .updateValue(maxValue); - - service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature) - .setProps({ + service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).updateValue(maxValue); + + service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).setProps({ + minValue: minValue, + maxValue: maxValue, + minStep: minStep, + }); + + if (this.accessory.context.config.type === 'HEATING') { + if (service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).value < minValue) + service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).updateValue(minValue); + + if (service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).value > maxValue) + service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).updateValue(maxValue); + + service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).setProps({ minValue: minValue, maxValue: maxValue, - minStep: minStep + minStep: minStep, }); - - if(this.accessory.context.config.type === 'HEATING'){ - - if (service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).value < minValue) - service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature) - .updateValue(minValue); - - if (service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).value > maxValue) - service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature) - .updateValue(maxValue); - - service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature) - .setProps({ - minValue: minValue, - maxValue: maxValue, - minStep: minStep - }); - } - + if (!service.testCharacteristic(this.api.hap.Characteristic.ValvePosition)) service.addCharacteristic(this.api.hap.Characteristic.ValvePosition); - - this.historyService = new this.FakeGatoHistoryService('thermo', this.accessory, {storage:'fs', path: this.api.user.storagePath(), disableTimer:true}); - + + this.historyService = new this.FakeGatoHistoryService('thermo', this.accessory, { + storage: 'fs', + path: this.api.user.storagePath(), + disableTimer: true, + }); + await timeout(250); //wait for historyService to load - - service.getCharacteristic(this.api.hap.Characteristic.Active) - .onSet(value => { - - if(this.waitForEndValue){ + + service + .getCharacteristic(this.api.hap.Characteristic.Active) + .onSet((value) => { + if (this.waitForEndValue) { clearTimeout(this.waitForEndValue); this.waitForEndValue = null; } - + this.waitForEndValue = setTimeout(() => { - this.deviceHandler.setStates(this.accessory, this.accessories, 'State', value); - }, 500); - }) - .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)); - - service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature) - .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)); - - service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature) - .onSet(value => { - - if(this.waitForEndValue){ + .on( + 'change', + this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName) + ); + + service + .getCharacteristic(this.api.hap.Characteristic.CurrentTemperature) + .on( + 'change', + this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName) + ); + + service + .getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature) + .onSet((value) => { + if (this.waitForEndValue) { clearTimeout(this.waitForEndValue); this.waitForEndValue = null; } - + this.waitForEndValue = setTimeout(() => { - this.deviceHandler.setStates(this.accessory, this.accessories, 'Temperature', value); - }, 250); - }) - .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)); - - service.getCharacteristic(this.api.hap.Characteristic.ValvePosition) - .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)); - + .on( + 'change', + this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName) + ); + + service + .getCharacteristic(this.api.hap.Characteristic.ValvePosition) + .on( + 'change', + this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName) + ); + this.refreshHistory(service); - } - - refreshHistory(service){ - - let currentState = service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState).value; - let currentTemp = service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature).value; - let targetTemp = service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).value; - - let valvePos = currentTemp <= targetTemp && currentState !== 0 - ? Math.round(((targetTemp - currentTemp) >= 5 ? 100 : (targetTemp - currentTemp) * 20)) - : 0; - - //Thermo + + refreshHistory(service) { + let currentState = service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState).value; + let currentTemp = service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature).value; + let targetTemp = service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).value; + + let valvePos = + currentTemp <= targetTemp && currentState !== 0 + ? Math.round(targetTemp - currentTemp >= 5 ? 100 : (targetTemp - currentTemp) * 20) + : 0; + + //Thermo this.historyService.addEntry({ - time: moment().unix(), - currentTemp: currentTemp, - setTemp: targetTemp, - valvePosition: valvePos + time: moment().unix(), + currentTemp: currentTemp, + setTemp: targetTemp, + valvePosition: valvePos, }); - + setTimeout(() => { this.refreshHistory(service); }, 10 * 60 * 1000); - } - } module.exports = HeaterCoolerAccessory; diff --git a/src/accessories/humidity.js b/src/accessories/humidity.js index 350903c..853f443 100644 --- a/src/accessories/humidity.js +++ b/src/accessories/humidity.js @@ -7,78 +7,84 @@ const moment = require('moment'); const timeout = (ms) => new Promise((res) => setTimeout(res, ms)); class HumidityAccessory { - - constructor (api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { - + constructor(api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { this.api = api; this.accessory = accessory; this.accessories = accessories; this.FakeGatoHistoryService = FakeGatoHistoryService; - + this.deviceHandler = deviceHandler; this.tado = tado; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - async getService () { - + async getService() { let service = this.accessory.getService(this.api.hap.Service.HumiditySensor); - - if(!service){ + + if (!service) { Logger.info('Adding HumiditySensor service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.HumiditySensor, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.HumiditySensor, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } let batteryService = this.accessory.getService(this.api.hap.Service.BatteryService); - - if(!this.accessory.context.config.noBattery && this.accessory.context.config.type === 'HEATING'){ - if(!batteryService){ + + if (!this.accessory.context.config.noBattery && this.accessory.context.config.type === 'HEATING') { + if (!batteryService) { Logger.info('Adding Battery service', this.accessory.displayName); batteryService = this.accessory.addService(this.api.hap.Service.BatteryService); } - batteryService - .setCharacteristic(this.api.hap.Characteristic.ChargingState, this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE); + batteryService.setCharacteristic( + this.api.hap.Characteristic.ChargingState, + this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE + ); } else { - if(batteryService){ + if (batteryService) { Logger.info('Removing Battery service', this.accessory.displayName); this.accessory.removeService(batteryService); } } - - this.historyService = new this.FakeGatoHistoryService('room', this.accessory, {storage:'fs', path: this.api.user.storagePath(), disableTimer:true}); - + + this.historyService = new this.FakeGatoHistoryService('room', this.accessory, { + storage: 'fs', + path: this.api.user.storagePath(), + disableTimer: true, + }); + await timeout(250); //wait for historyService to load - - service.getCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity) - .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)); - + + service + .getCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity) + .on( + 'change', + this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName) + ); + this.refreshHistory(service); - } - - refreshHistory(service){ - + + refreshHistory(service) { let state = service.getCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity).value; - + this.historyService.addEntry({ - time: moment().unix(), + time: moment().unix(), temp: 0, humidity: state, - ppm: 0 + ppm: 0, }); - + setTimeout(() => { this.refreshHistory(service); }, 10 * 60 * 1000); - } - } -module.exports = HumidityAccessory; \ No newline at end of file +module.exports = HumidityAccessory; diff --git a/src/accessories/lightbulb.js b/src/accessories/lightbulb.js index 275507e..4af6ac2 100644 --- a/src/accessories/lightbulb.js +++ b/src/accessories/lightbulb.js @@ -3,59 +3,57 @@ const Logger = require('../helper/logger.js'); class SolarLightbulbAccessory { - - constructor (api, accessory, accessories, tado) { - + constructor(api, accessory, accessories, tado) { this.api = api; this.accessory = accessory; this.accessories = accessories; - + this.tado = tado; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - getService () { - + getService() { let service = this.accessory.getService(this.api.hap.Service.Lightbulb); let serviceOld = this.accessory.getService(this.api.hap.Service.LightSensor); - - if(serviceOld){ + + if (serviceOld) { Logger.info('Removing LightSensor service', this.accessory.displayName); this.accessory.removeService(serviceOld); } - - if(!service){ + + if (!service) { Logger.info('Adding Lightbulb service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.Lightbulb, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.Lightbulb, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - - if(!service.testCharacteristic(this.api.hap.Characteristic.Brightness)) - service.addCharacteristic(this.api.hap.Characteristic.Brightness); - - service.getCharacteristic(this.api.hap.Characteristic.On) - .onSet(() => { - setTimeout(() => { - service.getCharacteristic(this.api.hap.Characteristic.On) - .updateValue(this.accessory.context.lightBulbState || false); - }, 500); - }); - - service.getCharacteristic(this.api.hap.Characteristic.Brightness) - .onSet(() => { - setTimeout(() => { - service.getCharacteristic(this.api.hap.Characteristic.Brightness) - .updateValue(this.accessory.context.lightBulbBrightness || 0); - }, 500); - }); - - } + if (!service.testCharacteristic(this.api.hap.Characteristic.Brightness)) + service.addCharacteristic(this.api.hap.Characteristic.Brightness); + + service.getCharacteristic(this.api.hap.Characteristic.On).onSet(() => { + setTimeout(() => { + service + .getCharacteristic(this.api.hap.Characteristic.On) + .updateValue(this.accessory.context.lightBulbState || false); + }, 500); + }); + + service.getCharacteristic(this.api.hap.Characteristic.Brightness).onSet(() => { + setTimeout(() => { + service + .getCharacteristic(this.api.hap.Characteristic.Brightness) + .updateValue(this.accessory.context.lightBulbBrightness || 0); + }, 500); + }); + } } -module.exports = SolarLightbulbAccessory; \ No newline at end of file +module.exports = SolarLightbulbAccessory; diff --git a/src/accessories/lightsensor.js b/src/accessories/lightsensor.js index 3a2f056..28ba378 100644 --- a/src/accessories/lightsensor.js +++ b/src/accessories/lightsensor.js @@ -3,40 +3,38 @@ const Logger = require('../helper/logger.js'); class SolarLightsensorAccessory { - - constructor (api, accessory, accessories, tado) { - + constructor(api, accessory, accessories, tado) { this.api = api; this.accessory = accessory; this.accessories = accessories; - + this.tado = tado; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - getService () { - + getService() { let service = this.accessory.getService(this.api.hap.Service.LightSensor); let serviceOld = this.accessory.getService(this.api.hap.Service.Lightbulb); - - if(serviceOld){ + + if (serviceOld) { Logger.info('Removing Lightbulb service', this.accessory.displayName); this.accessory.removeService(serviceOld); } - - if(!service){ + + if (!service) { Logger.info('Adding LightSensor service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.LightSensor, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.LightSensor, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - } - } -module.exports = SolarLightsensorAccessory; \ No newline at end of file +module.exports = SolarLightsensorAccessory; diff --git a/src/accessories/motion.js b/src/accessories/motion.js index e257e40..0af6a73 100644 --- a/src/accessories/motion.js +++ b/src/accessories/motion.js @@ -7,69 +7,73 @@ const moment = require('moment'); const timeout = (ms) => new Promise((res) => setTimeout(res, ms)); class MotionAccessory { - - constructor (api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { - + constructor(api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { this.api = api; this.accessory = accessory; this.accessories = accessories; this.FakeGatoHistoryService = FakeGatoHistoryService; - + this.deviceHandler = deviceHandler; this.tado = tado; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - async getService () { - + async getService() { let service = this.accessory.getService(this.api.hap.Service.MotionSensor); let serviceOld = this.accessory.getService(this.api.hap.Service.OccupancySensor); - - if(serviceOld){ + + if (serviceOld) { Logger.info('Removing Occupancy service', this.accessory.displayName); this.accessory.removeService(serviceOld); } - - if(!service){ + + if (!service) { Logger.info('Adding Motion service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.MotionSensor, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.MotionSensor, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - - if(!service.testCharacteristic(this.api.hap.Characteristic.LastActivation)) + + if (!service.testCharacteristic(this.api.hap.Characteristic.LastActivation)) service.addCharacteristic(this.api.hap.Characteristic.LastActivation); - - this.historyService = new this.FakeGatoHistoryService('motion', this.accessory, {storage:'fs', path: this.api.user.storagePath(), disableTimer:true}); - + + this.historyService = new this.FakeGatoHistoryService('motion', this.accessory, { + storage: 'fs', + path: this.api.user.storagePath(), + disableTimer: true, + }); + await timeout(250); //wait for historyService to load - - service.getCharacteristic(this.api.hap.Characteristic.MotionDetected) - .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)); - + + service + .getCharacteristic(this.api.hap.Characteristic.MotionDetected) + .on( + 'change', + this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName) + ); + this.refreshHistory(service); - } - - async refreshHistory(service){ - + + async refreshHistory(service) { let state = service.getCharacteristic(this.api.hap.Characteristic.MotionDetected).value; - + this.historyService.addEntry({ - time: moment().unix(), - status: state ? 1 : 0 + time: moment().unix(), + status: state ? 1 : 0, }); - + setTimeout(() => { this.refreshHistory(service); }, 10 * 60 * 1000); - } - } -module.exports = MotionAccessory; \ No newline at end of file +module.exports = MotionAccessory; diff --git a/src/accessories/occupancy.js b/src/accessories/occupancy.js index 2e1546a..18b6100 100644 --- a/src/accessories/occupancy.js +++ b/src/accessories/occupancy.js @@ -3,44 +3,43 @@ const Logger = require('../helper/logger.js'); class OccupancyAccessory { - - constructor (api, accessory, accessories, tado, deviceHandler) { - + constructor(api, accessory, accessories, tado, deviceHandler) { this.api = api; this.accessory = accessory; this.accessories = accessories; - + this.deviceHandler = deviceHandler; this.tado = tado; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - async getService () { - + async getService() { let service = this.accessory.getService(this.api.hap.Service.OccupancySensor); let serviceOld = this.accessory.getService(this.api.hap.Service.MotionSensor); - - if(serviceOld){ + + if (serviceOld) { Logger.info('Removing Motion service', this.accessory.displayName); this.accessory.removeService(serviceOld); } - - if(!service){ + + if (!service) { Logger.info('Adding Occupancy service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.OccupancySensor, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.OccupancySensor, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - - service.getCharacteristic(this.api.hap.Characteristic.OccupancyDetected) + + service + .getCharacteristic(this.api.hap.Characteristic.OccupancyDetected) .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, false, this.accessory.displayName)); - } - } -module.exports = OccupancyAccessory; \ No newline at end of file +module.exports = OccupancyAccessory; diff --git a/src/accessories/security.js b/src/accessories/security.js index ca42302..62a0a8e 100644 --- a/src/accessories/security.js +++ b/src/accessories/security.js @@ -3,77 +3,77 @@ const Logger = require('../helper/logger.js'); class SecurityAccessory { - - constructor (api, accessory, accessories, tado, deviceHandler) { - + constructor(api, accessory, accessories, tado, deviceHandler) { this.api = api; this.accessory = accessory; this.accessories = accessories; - + this.deviceHandler = deviceHandler; this.tado = tado; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - getService () { - + getService() { let service = this.accessory.getService(this.api.hap.Service.SecuritySystem); let serviceOld = this.accessory.getService(this.api.hap.Service.Switch); - + let serviceHomeSwitch = this.accessory.getServiceById(this.api.hap.Service.Switch, 'HomeSwitch'); let serviceAwaySwitch = this.accessory.getServiceById(this.api.hap.Service.Switch, 'AwaySwitch'); - - if(serviceHomeSwitch){ + + if (serviceHomeSwitch) { Logger.info('Removing Switch service (home)', this.accessory.displayName); this.accessory.removeService(serviceHomeSwitch); } - - if(serviceAwaySwitch){ + + if (serviceAwaySwitch) { Logger.info('Removing Switch service (away)', this.accessory.displayName); this.accessory.removeService(serviceAwaySwitch); } - - if(serviceOld){ + + if (serviceOld) { Logger.info('Removing Switch service', this.accessory.displayName); this.accessory.removeService(serviceOld); } - - if(!service){ + + if (!service) { Logger.info('Adding SecuritySystem service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.SecuritySystem, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.SecuritySystem, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - + service .setCharacteristic(this.api.hap.Characteristic.Name, this.accessory.displayName) .setCharacteristic(this.api.hap.Characteristic.SecuritySystemAlarmType, 0) .setCharacteristic(this.api.hap.Characteristic.StatusFault, this.api.hap.Characteristic.StatusFault.NO_FAULT) - .setCharacteristic(this.api.hap.Characteristic.StatusTampered, this.api.hap.Characteristic.StatusTampered.NOT_TAMPERED); - - service.getCharacteristic(this.api.hap.Characteristic.SecuritySystemCurrentState) - .setProps({ - maxValue: 3, - minValue: 0, - validValues: [0, 1, 3] - }); - - service.getCharacteristic(this.api.hap.Characteristic.SecuritySystemTargetState) - .setProps({ - maxValue: 3, - minValue: 0, - validValues: [0, 1, 3] - }); - - service.getCharacteristic(this.api.hap.Characteristic.SecuritySystemTargetState) + .setCharacteristic( + this.api.hap.Characteristic.StatusTampered, + this.api.hap.Characteristic.StatusTampered.NOT_TAMPERED + ); + + service.getCharacteristic(this.api.hap.Characteristic.SecuritySystemCurrentState).setProps({ + maxValue: 3, + minValue: 0, + validValues: [0, 1, 3], + }); + + service.getCharacteristic(this.api.hap.Characteristic.SecuritySystemTargetState).setProps({ + maxValue: 3, + minValue: 0, + validValues: [0, 1, 3], + }); + + service + .getCharacteristic(this.api.hap.Characteristic.SecuritySystemTargetState) .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, 'State')); - } - } -module.exports = SecurityAccessory; \ No newline at end of file +module.exports = SecurityAccessory; diff --git a/src/accessories/switch.js b/src/accessories/switch.js index fb0adf1..7873e69 100644 --- a/src/accessories/switch.js +++ b/src/accessories/switch.js @@ -3,92 +3,95 @@ const Logger = require('../helper/logger.js'); class SwitchAccessory { - - constructor (api, accessory, accessories, tado, deviceHandler) { - + constructor(api, accessory, accessories, tado, deviceHandler) { this.api = api; this.accessory = accessory; this.accessories = accessories; - + this.deviceHandler = deviceHandler; this.tado = tado; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - getService () { - + getService() { let service = this.accessory.getService(this.api.hap.Service.Switch); - + let serviceContact = this.accessory.getService(this.api.hap.Service.ContactSensor); let serviceHeater = this.accessory.getService(this.api.hap.Service.HeaterCooler); let serviceFaucet = this.accessory.getService(this.api.hap.Service.Valve); let serviceSecurity = this.accessory.getService(this.api.hap.Service.SecuritySystem); let serviceThermostat = this.accessory.getService(this.api.hap.Service.Thermostat); - + let serviceHomeSwitch = this.accessory.getServiceById(this.api.hap.Service.Switch, 'HomeSwitch'); let serviceAwaySwitch = this.accessory.getServiceById(this.api.hap.Service.Switch, 'AwaySwitch'); - - if(serviceContact){ + + if (serviceContact) { Logger.info('Removing ContactSensor service', this.accessory.displayName); this.accessory.removeService(serviceContact); } - - if(serviceHeater){ + + if (serviceHeater) { Logger.info('Removing HeaterCooler service', this.accessory.displayName); this.accessory.removeService(serviceHeater); } - - if(serviceThermostat){ + + if (serviceThermostat) { Logger.info('Removing Thermostat service', this.accessory.displayName); this.accessory.removeService(serviceThermostat); } - - if(serviceFaucet){ + + if (serviceFaucet) { Logger.info('Removing Faucet service', this.accessory.displayName); this.accessory.removeService(serviceFaucet); } - - if(serviceSecurity){ + + if (serviceSecurity) { Logger.info('Removing Security service', this.accessory.displayName); this.accessory.removeService(serviceSecurity); } - - if(!service && this.accessory.context.config.subtype !== 'extra-plockswitch' && this.accessory.context.config.subtype !== 'extra-childswitch' && this.accessory.context.config.subtype !== 'zone-window-switch' && this.accessory.context.config.subtype !== 'extra-cntrlswitch'){ + + if ( + !service && + this.accessory.context.config.subtype !== 'extra-plockswitch' && + this.accessory.context.config.subtype !== 'extra-childswitch' && + this.accessory.context.config.subtype !== 'zone-window-switch' && + this.accessory.context.config.subtype !== 'extra-cntrlswitch' + ) { Logger.info('Adding Switch service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.Switch, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.Switch, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - - if(this.accessory.context.config.subtype === 'extra-plockswitch'){ - if(!serviceHomeSwitch){ + if (this.accessory.context.config.subtype === 'extra-plockswitch') { + if (!serviceHomeSwitch) { Logger.info('Adding Switch service (home)', this.accessory.displayName); serviceHomeSwitch = this.accessory.addService(this.api.hap.Service.Switch, 'Home', 'HomeSwitch'); } - - if(!serviceAwaySwitch){ + + if (!serviceAwaySwitch) { Logger.info('Adding Switch service (away)', this.accessory.displayName); serviceAwaySwitch = this.accessory.addService(this.api.hap.Service.Switch, 'Away', 'AwaySwitch'); } - } - - if(this.accessory.context.config.subtype === 'extra-childswitch'){ - - this.accessory.services.forEach(service => { - if(service.subtype){ + + if (this.accessory.context.config.subtype === 'extra-childswitch') { + this.accessory.services.forEach((service) => { + if (service.subtype) { let found = false; - this.accessory.context.config.childLocks.forEach(childLock => { - if(service.subtype === childLock.serialNumber){ + this.accessory.context.config.childLocks.forEach((childLock) => { + if (service.subtype === childLock.serialNumber) { found = true; } }); - if(!found){ + if (!found) { Logger.info('Removing Switch service (' + service.displayName + ')', this.accessory.displayName); let removableService = this.accessory.getServiceById(this.api.hap.Service.Switch, service.subtype); this.accessory.removeService(removableService); @@ -96,126 +99,122 @@ class SwitchAccessory { } }); - this.accessory.context.config.childLocks.forEach(childLock => { - + this.accessory.context.config.childLocks.forEach((childLock) => { let serviceChildLock = this.accessory.getServiceById(this.api.hap.Service.Switch, childLock.serialNumber); - - if(!serviceChildLock){ + + if (!serviceChildLock) { Logger.info('Adding Switch service (' + childLock.name + ')', this.accessory.displayName); - serviceChildLock = this.accessory.addService(this.api.hap.Service.Switch, childLock.name, childLock.serialNumber); + serviceChildLock = this.accessory.addService( + this.api.hap.Service.Switch, + childLock.name, + childLock.serialNumber + ); } - - serviceChildLock.getCharacteristic(this.api.hap.Characteristic.On) - .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, childLock.serialNumber)); - + + serviceChildLock + .getCharacteristic(this.api.hap.Characteristic.On) + .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, childLock.serialNumber)); }); - } - - if(this.accessory.context.config.subtype === 'extra-cntrlswitch'){ - - this.accessory.services.forEach(service => { - if(service.subtype){ + + if (this.accessory.context.config.subtype === 'extra-cntrlswitch') { + this.accessory.services.forEach((service) => { + if (service.subtype) { let found = false; - this.accessory.context.config.switches.forEach(sub => { - if(service.subtype === sub.sub){ + this.accessory.context.config.switches.forEach((sub) => { + if (service.subtype === sub.sub) { found = true; } }); - if(!found){ + if (!found) { Logger.info('Removing Switch service (' + service.displayName + ')', this.accessory.displayName); let removableService = this.accessory.getServiceById(this.api.hap.Service.Switch, service.subtype); this.accessory.removeService(removableService); } } }); - - this.accessory.context.config.switches.forEach(sub => { - + + this.accessory.context.config.switches.forEach((sub) => { let serviceSubSwitch = this.accessory.getServiceById(this.api.hap.Service.Switch, sub.sub); - - if(!serviceSubSwitch){ + + if (!serviceSubSwitch) { Logger.info('Adding Switch service (' + sub.name + ')', this.accessory.displayName); serviceSubSwitch = this.accessory.addService(this.api.hap.Service.Switch, sub.name, sub.sub); } - - if(sub.name === 'Central') { - + + if (sub.name === 'Central') { //Modes - if(!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.AutoThermostats)) + if (!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.AutoThermostats)) serviceSubSwitch.addCharacteristic(this.api.hap.Characteristic.AutoThermostats); - - if(!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.ManualThermostats)) + + if (!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.ManualThermostats)) serviceSubSwitch.addCharacteristic(this.api.hap.Characteristic.ManualThermostats); - - if(!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OfflineThermostats)) - serviceSubSwitch.addCharacteristic(this.api.hap.Characteristic.OfflineThermostats); - + + if (!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OfflineThermostats)) + serviceSubSwitch.addCharacteristic(this.api.hap.Characteristic.OfflineThermostats); + //Activity - if(this.accessory.context.config.runningInformation){ - - if(!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatDay)) + if (this.accessory.context.config.runningInformation) { + if (!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatDay)) serviceSubSwitch.addCharacteristic(this.api.hap.Characteristic.OverallHeatDay); - - if(!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatMonth)) + + if (!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatMonth)) serviceSubSwitch.addCharacteristic(this.api.hap.Characteristic.OverallHeatMonth); - - if(!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatYear)) - serviceSubSwitch.addCharacteristic(this.api.hap.Characteristic.OverallHeatYear); - + + if (!serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatYear)) + serviceSubSwitch.addCharacteristic(this.api.hap.Characteristic.OverallHeatYear); } else { - - if(serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatDay)) - serviceSubSwitch.removeCharacteristic(serviceSubSwitch.getCharacteristic(this.api.hap.Characteristic.OverallHeatDay)); - - if(serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatMonth)) - serviceSubSwitch.removeCharacteristic(serviceSubSwitch.getCharacteristic(this.api.hap.Characteristic.OverallHeatMonth)); - - if(serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatYear)) - serviceSubSwitch.removeCharacteristic(serviceSubSwitch.getCharacteristic(this.api.hap.Characteristic.OverallHeatYear)); - + if (serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatDay)) + serviceSubSwitch.removeCharacteristic( + serviceSubSwitch.getCharacteristic(this.api.hap.Characteristic.OverallHeatDay) + ); + + if (serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatMonth)) + serviceSubSwitch.removeCharacteristic( + serviceSubSwitch.getCharacteristic(this.api.hap.Characteristic.OverallHeatMonth) + ); + + if (serviceSubSwitch.testCharacteristic(this.api.hap.Characteristic.OverallHeatYear)) + serviceSubSwitch.removeCharacteristic( + serviceSubSwitch.getCharacteristic(this.api.hap.Characteristic.OverallHeatYear) + ); } - - serviceSubSwitch.getCharacteristic(this.api.hap.Characteristic.On) + + serviceSubSwitch + .getCharacteristic(this.api.hap.Characteristic.On) .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, sub.name)); - - } else if(sub.name === 'Dummy') { - + } else if (sub.name === 'Dummy') { this.accessory.context.dummyState = this.accessory.context.dummyState || false; - - serviceSubSwitch.getCharacteristic(this.api.hap.Characteristic.On) + + serviceSubSwitch + .getCharacteristic(this.api.hap.Characteristic.On) .onGet(() => { return this.accessory.context.dummyState; }) - .onSet(state => { + .onSet((state) => { Logger.info('Dummy: ' + state, this.accessory.displayName); this.accessory.context.dummyState = state; }) .updateValue(this.accessory.context.dummyState); - } else { - - serviceSubSwitch.getCharacteristic(this.api.hap.Characteristic.On) + serviceSubSwitch + .getCharacteristic(this.api.hap.Characteristic.On) .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, sub.name)) - .updateValue(false); - + .updateValue(false); } - }); - } - - if(this.accessory.context.config.subtype === 'zone-window-switch'){ - - this.accessory.services.forEach(service => { - if(service.subtype){ + + if (this.accessory.context.config.subtype === 'zone-window-switch') { + this.accessory.services.forEach((service) => { + if (service.subtype) { let found = false; - this.accessory.context.config.openWindows.forEach(window => { - if(service.subtype === window.name){ + this.accessory.context.config.openWindows.forEach((window) => { + if (service.subtype === window.name) { found = true; } }); - if(!found){ + if (!found) { Logger.info('Removing Switch service (' + service.displayName + ')', this.accessory.displayName); let removableService = this.accessory.getServiceById(this.api.hap.Service.Switch, service.subtype); this.accessory.removeService(removableService); @@ -223,39 +222,40 @@ class SwitchAccessory { } }); - this.accessory.context.config.openWindows.forEach(window => { - + this.accessory.context.config.openWindows.forEach((window) => { let serviceSwitch = this.accessory.getServiceById(this.api.hap.Service.Switch, window.name); - - if(!serviceSwitch){ + + if (!serviceSwitch) { Logger.info('Adding Switch service (' + window.name + ')', this.accessory.displayName); serviceSwitch = this.accessory.addService(this.api.hap.Service.Switch, window.name, window.name); } - - serviceSwitch.getCharacteristic(this.api.hap.Characteristic.On) - .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, window.name + '-' + window.zoneId)); - + + serviceSwitch + .getCharacteristic(this.api.hap.Characteristic.On) + .onSet( + this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, window.name + '-' + window.zoneId) + ); }); - } - - if(this.accessory.context.config.subtype === 'extra-plockswitch'){ - - serviceHomeSwitch.getCharacteristic(this.api.hap.Characteristic.On) - .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, 'Home')); - - serviceAwaySwitch.getCharacteristic(this.api.hap.Characteristic.On) - .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, 'Away')); - - } else if(this.accessory.context.config.subtype !== 'extra-childswitch' && this.accessory.context.config.subtype !== 'zone-window-switch' && this.accessory.context.config.subtype !== 'extra-cntrlswitch') { - - service.getCharacteristic(this.api.hap.Characteristic.On) - .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, 'Trigger State')); - + + if (this.accessory.context.config.subtype === 'extra-plockswitch') { + serviceHomeSwitch + .getCharacteristic(this.api.hap.Characteristic.On) + .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, 'Home')); + + serviceAwaySwitch + .getCharacteristic(this.api.hap.Characteristic.On) + .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, 'Away')); + } else if ( + this.accessory.context.config.subtype !== 'extra-childswitch' && + this.accessory.context.config.subtype !== 'zone-window-switch' && + this.accessory.context.config.subtype !== 'extra-cntrlswitch' + ) { + service + .getCharacteristic(this.api.hap.Characteristic.On) + .onSet(this.deviceHandler.setStates.bind(this, this.accessory, this.accessories, 'Trigger State')); } - } - } module.exports = SwitchAccessory; diff --git a/src/accessories/temperature.js b/src/accessories/temperature.js index 85a3f5e..d7db90c 100644 --- a/src/accessories/temperature.js +++ b/src/accessories/temperature.js @@ -7,84 +7,89 @@ const moment = require('moment'); const timeout = (ms) => new Promise((res) => setTimeout(res, ms)); class TemperatureAccessory { - - constructor (api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { - + constructor(api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { this.api = api; this.accessory = accessory; this.accessories = accessories; this.FakeGatoHistoryService = FakeGatoHistoryService; - + this.deviceHandler = deviceHandler; this.tado = tado; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - async getService () { - + async getService() { let service = this.accessory.getService(this.api.hap.Service.TemperatureSensor); - - if(!service){ + + if (!service) { Logger.info('Adding Temperature service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.TemperatureSensor, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.TemperatureSensor, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - + let batteryService = this.accessory.getService(this.api.hap.Service.BatteryService); - - if(!this.accessory.context.config.noBattery && this.accessory.context.config.type === 'HEATING'){ - if(!batteryService){ + + if (!this.accessory.context.config.noBattery && this.accessory.context.config.type === 'HEATING') { + if (!batteryService) { Logger.info('Adding Battery service', this.accessory.displayName); batteryService = this.accessory.addService(this.api.hap.Service.BatteryService); } - batteryService - .setCharacteristic(this.api.hap.Characteristic.ChargingState, this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE); + batteryService.setCharacteristic( + this.api.hap.Characteristic.ChargingState, + this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE + ); } else { - if(batteryService){ + if (batteryService) { Logger.info('Removing Battery service', this.accessory.displayName); this.accessory.removeService(batteryService); } } - - service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature) - .setProps({ - minValue: -100, - maxValue: 100 - }); - - this.historyService = new this.FakeGatoHistoryService('room', this.accessory, {storage:'fs', path: this.api.user.storagePath(), disableTimer:true}); - + + service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature).setProps({ + minValue: -100, + maxValue: 100, + }); + + this.historyService = new this.FakeGatoHistoryService('room', this.accessory, { + storage: 'fs', + path: this.api.user.storagePath(), + disableTimer: true, + }); + await timeout(250); //wait for historyService to load - - service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature) - .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)); - + + service + .getCharacteristic(this.api.hap.Characteristic.CurrentTemperature) + .on( + 'change', + this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName) + ); + this.refreshHistory(service); - } - - refreshHistory(service){ - + + refreshHistory(service) { let state = service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature).value; - + this.historyService.addEntry({ - time: moment().unix(), + time: moment().unix(), temp: state, humidity: 0, - ppm: 0 + ppm: 0, }); - + setTimeout(() => { this.refreshHistory(service); }, 10 * 60 * 1000); - } - } -module.exports = TemperatureAccessory; \ No newline at end of file +module.exports = TemperatureAccessory; diff --git a/src/accessories/thermostat.js b/src/accessories/thermostat.js index 98c6c93..b7ab396 100644 --- a/src/accessories/thermostat.js +++ b/src/accessories/thermostat.js @@ -8,362 +8,330 @@ const moment = require('moment'); const timeout = (ms) => new Promise((res) => setTimeout(res, ms)); class ThermostatAccessory { - - constructor (api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { - + constructor(api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) { this.api = api; this.accessory = accessory; - this.accessories = accessories; + this.accessories = accessories; this.FakeGatoHistoryService = FakeGatoHistoryService; - + this.deviceHandler = deviceHandler; this.tado = tado; - + this.autoDelayTimeout = null; - - this.getService(); + this.getService(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Services //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - async getService () { - + async getService() { let service = this.accessory.getService(this.api.hap.Service.Thermostat); let serviceOld = this.accessory.getService(this.api.hap.Service.HeaterCooler); - - if(serviceOld){ + + if (serviceOld) { Logger.info('Removing HeaterCooler service', this.accessory.displayName); this.accessory.removeService(serviceOld); } - if(!service){ + if (!service) { Logger.info('Adding Thermostat service', this.accessory.displayName); - service = this.accessory.addService(this.api.hap.Service.Thermostat, this.accessory.displayName, this.accessory.context.config.subtype); + service = this.accessory.addService( + this.api.hap.Service.Thermostat, + this.accessory.displayName, + this.accessory.context.config.subtype + ); } - + let batteryService = this.accessory.getService(this.api.hap.Service.BatteryService); - - if(!this.accessory.context.config.noBattery){ - if(!batteryService){ + + if (!this.accessory.context.config.noBattery) { + if (!batteryService) { Logger.info('Adding Battery service', this.accessory.displayName); batteryService = this.accessory.addService(this.api.hap.Service.BatteryService); } - batteryService - .setCharacteristic(this.api.hap.Characteristic.ChargingState, this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE); + batteryService.setCharacteristic( + this.api.hap.Characteristic.ChargingState, + this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE + ); } else { - if(batteryService){ + if (batteryService) { Logger.info('Removing Battery service', this.accessory.displayName); this.accessory.removeService(batteryService); } } - + //Handle AirQuality - if(this.accessory.context.config.airQuality && this.accessory.context.config.type !== 'HOT_WATER'){ - - if(!service.testCharacteristic(this.api.hap.Characteristic.AirQuality)) + if (this.accessory.context.config.airQuality && this.accessory.context.config.type !== 'HOT_WATER') { + if (!service.testCharacteristic(this.api.hap.Characteristic.AirQuality)) service.addCharacteristic(this.api.hap.Characteristic.AirQuality); - } else { - - if(service.testCharacteristic(this.api.hap.Characteristic.AirQuality)) + if (service.testCharacteristic(this.api.hap.Characteristic.AirQuality)) service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.AirQuality)); - } - + //Handle DelaySwitch - if(this.accessory.context.config.delaySwitch && this.accessory.context.config.type !== 'HOT_WATER'){ - - if(!service.testCharacteristic(this.api.hap.Characteristic.DelaySwitch)) + if (this.accessory.context.config.delaySwitch && this.accessory.context.config.type !== 'HOT_WATER') { + if (!service.testCharacteristic(this.api.hap.Characteristic.DelaySwitch)) service.addCharacteristic(this.api.hap.Characteristic.DelaySwitch); - - if(!service.testCharacteristic(this.api.hap.Characteristic.DelayTimer)) + + if (!service.testCharacteristic(this.api.hap.Characteristic.DelayTimer)) service.addCharacteristic(this.api.hap.Characteristic.DelayTimer); - - if(this.accessory.context.config.autoOffDelay){ - - service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch) - .onSet(value => { - if(value && this.accessory.context.delayTimer){ + + if (this.accessory.context.config.autoOffDelay) { + service + .getCharacteristic(this.api.hap.Characteristic.DelaySwitch) + .onSet((value) => { + if (value && this.accessory.context.delayTimer) { this.autoDelayTimeout = setTimeout(() => { Logger.info('Timer expired, turning off delay switch', this.accessory.displayName); - service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch) - .updateValue(false); + service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch).updateValue(false); this.autoDelayTimeout = null; }, this.accessory.context.delayTimer * 1000); } else { - if(this.autoDelayTimeout){ + if (this.autoDelayTimeout) { clearTimeout(this.autoDelayTimeout); this.autoDelayTimeout = null; } - } + } }) .updateValue(false); - } else { - - service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch) + service + .getCharacteristic(this.api.hap.Characteristic.DelaySwitch) .onGet(() => { return this.accessory.context.delaySwitch || false; }) - .onSet(value => { + .onSet((value) => { this.accessory.context.delaySwitch = value; }); - } - - service.getCharacteristic(this.api.hap.Characteristic.DelayTimer) + + service + .getCharacteristic(this.api.hap.Characteristic.DelayTimer) .onGet(() => { return this.accessory.context.delayTimer || 0; }) - .onSet(value => { + .onSet((value) => { this.accessory.context.delayTimer = value; }); - - } else { - - if(service.testCharacteristic(this.api.hap.Characteristic.DelaySwitch)) + if (service.testCharacteristic(this.api.hap.Characteristic.DelaySwitch)) service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch)); - - if(service.testCharacteristic(this.api.hap.Characteristic.DelayTimer)) + + if (service.testCharacteristic(this.api.hap.Characteristic.DelayTimer)) service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.DelayTimer)); - } - - let minValue = this.accessory.context.config.type === 'HOT_WATER' - ? this.accessory.context.config.temperatureUnit === 'CELSIUS' - ? 30 - : 86 - : this.accessory.context.config.temperatureUnit === 'CELSIUS' + + let minValue = + this.accessory.context.config.type === 'HOT_WATER' + ? this.accessory.context.config.temperatureUnit === 'CELSIUS' + ? 30 + : 86 + : this.accessory.context.config.temperatureUnit === 'CELSIUS' ? 5 : 41; - - let maxValue = this.accessory.context.config.type === 'HOT_WATER' - ? this.accessory.context.config.temperatureUnit === 'CELSIUS' - ? 65 - : 149 - : this.accessory.context.config.temperatureUnit === 'CELSIUS' + + let maxValue = + this.accessory.context.config.type === 'HOT_WATER' + ? this.accessory.context.config.temperatureUnit === 'CELSIUS' + ? 65 + : 149 + : this.accessory.context.config.temperatureUnit === 'CELSIUS' ? 25 : 77; - - minValue = this.accessory.context.config.minValue < maxValue - ? this.accessory.context.config.minValue - : minValue; - - maxValue = this.accessory.context.config.maxValue > minValue - ? this.accessory.context.config.maxValue - : maxValue; - - let minStep = parseFloat((this.accessory.context.config.minStep && !isNaN(this.accessory.context.config.minStep) && this.accessory.context.config.minStep > 0 && this.accessory.context.config.minStep <= 1 - ? parseFloat(this.accessory.context.config.minStep) - : 1).toFixed(2)); - + + minValue = this.accessory.context.config.minValue < maxValue ? this.accessory.context.config.minValue : minValue; + + maxValue = this.accessory.context.config.maxValue > minValue ? this.accessory.context.config.maxValue : maxValue; + + let minStep = parseFloat( + (this.accessory.context.config.minStep && + !isNaN(this.accessory.context.config.minStep) && + this.accessory.context.config.minStep > 0 && + this.accessory.context.config.minStep <= 1 + ? parseFloat(this.accessory.context.config.minStep) + : 1 + ).toFixed(2) + ); + if (service.getCharacteristic(this.api.hap.Characteristic.TargetHeatingCoolingState).value === 2) - service.getCharacteristic(this.api.hap.Characteristic.TargetHeatingCoolingState) - .updateValue(1); - - service.getCharacteristic(this.api.hap.Characteristic.TargetHeatingCoolingState) - .setProps({ - maxValue: 3, - validValues: [0, 1, 3] - }); - - service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature) - .setProps({ - minValue: -255, - maxValue: 255 - }); - + service.getCharacteristic(this.api.hap.Characteristic.TargetHeatingCoolingState).updateValue(1); + + service.getCharacteristic(this.api.hap.Characteristic.TargetHeatingCoolingState).setProps({ + maxValue: 3, + validValues: [0, 1, 3], + }); + + service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature).setProps({ + minValue: -255, + maxValue: 255, + }); + if (service.getCharacteristic(this.api.hap.Characteristic.TargetTemperature).value < minValue) - service.getCharacteristic(this.api.hap.Characteristic.TargetTemperature) - .updateValue(minValue); - + service.getCharacteristic(this.api.hap.Characteristic.TargetTemperature).updateValue(minValue); + if (service.getCharacteristic(this.api.hap.Characteristic.TargetTemperature).value > maxValue) - service.getCharacteristic(this.api.hap.Characteristic.TargetTemperature) - .updateValue(maxValue); - - service.getCharacteristic(this.api.hap.Characteristic.TargetTemperature) - .setProps({ - minValue: minValue, - maxValue: maxValue, - minStep: minStep - }); - - if (!this.accessory.context.config.separateHumidity){ - if(!service.testCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity)) + service.getCharacteristic(this.api.hap.Characteristic.TargetTemperature).updateValue(maxValue); + + service.getCharacteristic(this.api.hap.Characteristic.TargetTemperature).setProps({ + minValue: minValue, + maxValue: maxValue, + minStep: minStep, + }); + + if (!this.accessory.context.config.separateHumidity) { + if (!service.testCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity)) service.addCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity); } else { - if(service.testCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity)) + if (service.testCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity)) service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity)); } - + if (!service.testCharacteristic(this.api.hap.Characteristic.ValvePosition)) service.addCharacteristic(this.api.hap.Characteristic.ValvePosition); - - this.historyService = new this.FakeGatoHistoryService('thermo', this.accessory, {storage:'fs', path: this.api.user.storagePath(), disableTimer:true}); - + + this.historyService = new this.FakeGatoHistoryService('thermo', this.accessory, { + storage: 'fs', + path: this.api.user.storagePath(), + disableTimer: true, + }); + await timeout(250); //wait for historyService to load - - service.getCharacteristic(this.api.hap.Characteristic.TemperatureDisplayUnits) + + service + .getCharacteristic(this.api.hap.Characteristic.TemperatureDisplayUnits) .onSet(this.changeUnit.bind(this, service)); - - service.getCharacteristic(this.api.hap.Characteristic.TargetHeatingCoolingState) - .onSet(value => { - - if(this.waitForEndValue){ - clearTimeout(this.waitForEndValue); - this.waitForEndValue = null; - } - - this.waitForEndValue = setTimeout(() => { - - if(value === 3){ - - if(this.timeoutAuto){ - this.deviceHandler.setStates(this.accessory, this.accessories, 'State', value); - clearTimeout(this.timeoutAuto); - this.timeoutAuto = null; - } else { - this.deviceHandler.setStates(this.accessory, this.accessories, 'State', value); - } - + + service.getCharacteristic(this.api.hap.Characteristic.TargetHeatingCoolingState).onSet((value) => { + if (this.waitForEndValue) { + clearTimeout(this.waitForEndValue); + this.waitForEndValue = null; + } + + this.waitForEndValue = setTimeout(() => { + if (value === 3) { + if (this.timeoutAuto) { + this.deviceHandler.setStates(this.accessory, this.accessories, 'State', value); + clearTimeout(this.timeoutAuto); + this.timeoutAuto = null; } else { - this.deviceHandler.setStates(this.accessory, this.accessories, 'State', value); - } - - }, 500); - - }); + } else { + this.deviceHandler.setStates(this.accessory, this.accessories, 'State', value); + } + }, 500); + }); - service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature) - .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)); + service + .getCharacteristic(this.api.hap.Characteristic.CurrentTemperature) + .on( + 'change', + this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName) + ); - service.getCharacteristic(this.api.hap.Characteristic.TargetTemperature) - .onSet(value => { - + service + .getCharacteristic(this.api.hap.Characteristic.TargetTemperature) + .onSet((value) => { let tempUnit = service.getCharacteristic(this.api.hap.Characteristic.TemperatureDisplayUnits).value; - - let cToF = (c) => Math.round((c * 9/5) + 32); - let fToC = (f) => Math.round((f - 32) * 5/9); - - let newValue = tempUnit - ? value <= 25 - ? cToF(value) - : value - : value > 25 - ? fToC(value) - : value; - - service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature) - .updateValue(newValue); - + + let cToF = (c) => Math.round((c * 9) / 5 + 32); + let fToC = (f) => Math.round(((f - 32) * 5) / 9); + + let newValue = tempUnit ? (value <= 25 ? cToF(value) : value) : value > 25 ? fToC(value) : value; + + service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature).updateValue(newValue); + this.timeoutAuto = setTimeout(() => { - let targetState = service.getCharacteristic(this.api.hap.Characteristic.TargetHeatingCoolingState).value; - - if(targetState) - this.deviceHandler.setStates(this.accessory, this.accessories, 'Temperature', value); - + + if (targetState) this.deviceHandler.setStates(this.accessory, this.accessories, 'Temperature', value); + this.timeoutAuto = null; - }, 600); - }) - .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)); - - service.getCharacteristic(this.api.hap.Characteristic.ValvePosition) - .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)); - + .on( + 'change', + this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName) + ); + + service + .getCharacteristic(this.api.hap.Characteristic.ValvePosition) + .on( + 'change', + this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName) + ); + this.refreshHistory(service); - } - - refreshHistory(service){ - - let currentState = service.getCharacteristic(this.api.hap.Characteristic.CurrentHeatingCoolingState).value; - let targetState = service.getCharacteristic(this.api.hap.Characteristic.TargetHeatingCoolingState).value; - let currentTemp = service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature).value; - let targetTemp = service.getCharacteristic(this.api.hap.Characteristic.TargetTemperature).value; - - let valvePos = currentTemp <= targetTemp && currentState !== 0 && targetState !== 0 - ? Math.round(((targetTemp - currentTemp) >= 5 ? 100 : (targetTemp - currentTemp) * 20)) - : 0; - + + refreshHistory(service) { + let currentState = service.getCharacteristic(this.api.hap.Characteristic.CurrentHeatingCoolingState).value; + let targetState = service.getCharacteristic(this.api.hap.Characteristic.TargetHeatingCoolingState).value; + let currentTemp = service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature).value; + let targetTemp = service.getCharacteristic(this.api.hap.Characteristic.TargetTemperature).value; + + let valvePos = + currentTemp <= targetTemp && currentState !== 0 && targetState !== 0 + ? Math.round(targetTemp - currentTemp >= 5 ? 100 : (targetTemp - currentTemp) * 20) + : 0; + this.historyService.addEntry({ - time: moment().unix(), - currentTemp: currentTemp, - setTemp: targetTemp, - valvePosition: valvePos + time: moment().unix(), + currentTemp: currentTemp, + setTemp: targetTemp, + valvePosition: valvePos, }); - + setTimeout(() => { this.refreshHistory(service); }, 10 * 60 * 1000); - } - - async changeUnit(service, value){ - + + async changeUnit(service, value) { let charachteristicCurrentTemp = this.api.hap.Characteristic.CurrentTemperature; - - if(!value){ - + + if (!value) { //CELSIUS this.accessory.context.config.temperatureUnit = 'CELSIUS'; - - let fToC = (f) => Math.round((f - 32) * 5/9); - + + let fToC = (f) => Math.round(((f - 32) * 5) / 9); + let currentVal = service.getCharacteristic(charachteristicCurrentTemp).value; - - service.getCharacteristic(charachteristicCurrentTemp) - .updateValue(fToC(currentVal)); - + + service.getCharacteristic(charachteristicCurrentTemp).updateValue(fToC(currentVal)); } else { - //FAHRENHEIT this.accessory.context.config.temperatureUnit = 'FAHRENHEIT'; - - let cToF = (c) => Math.round((c * 9/5) + 32); - + + let cToF = (c) => Math.round((c * 9) / 5 + 32); + let currentVal = service.getCharacteristic(charachteristicCurrentTemp).value; - service.getCharacteristic(charachteristicCurrentTemp) - .updateValue(cToF(currentVal)); - + service.getCharacteristic(charachteristicCurrentTemp).updateValue(cToF(currentVal)); } - + try { - const configJSON = await fs.readJson(this.api.user.storagePath() + '/config.json'); - - for(const i in configJSON.platforms) - if(configJSON.platforms[i].platform === 'TadoPlatform') - for(const home in configJSON.platforms[i].homes) - if(configJSON.platforms[i].homes[home].name === this.accessory.context.config.homeName) - configJSON.platforms[i].homes[home].temperatureUnit = value - ? 'FAHRENHEIT' - : 'CELSIUS'; - + + for (const i in configJSON.platforms) + if (configJSON.platforms[i].platform === 'TadoPlatform') + for (const home in configJSON.platforms[i].homes) + if (configJSON.platforms[i].homes[home].name === this.accessory.context.config.homeName) + configJSON.platforms[i].homes[home].temperatureUnit = value ? 'FAHRENHEIT' : 'CELSIUS'; + fs.writeJsonSync(this.api.user.storagePath() + '/config.json', configJSON, { spaces: 4 }); - + Logger.info('New temperature unit stored in config', this.accessory.displayName); - - } catch(err) { - + } catch (err) { Logger.error('Error storing temperature unit in config!', this.accessory.displayName); Logger.error(err); - } - + return; - } - } module.exports = ThermostatAccessory; diff --git a/src/helper/handler.js b/src/helper/handler.js index 7af7d30..35970f0 100644 --- a/src/helper/handler.js +++ b/src/helper/handler.js @@ -10,447 +10,376 @@ var delayTimer = {}; const timeout = (ms) => new Promise((res) => setTimeout(res, ms)); module.exports = (api, accessories, config, tado, telegram) => { + async function setStates(accessory, accs, target, value) { + accessories = accs.filter((acc) => acc && acc.context.config.homeName === config.homeName); - async function setStates(accessory, accs, target, value){ - - accessories = accs.filter(acc => acc && acc.context.config.homeName === config.homeName); - try { - settingState = true; - - value = typeof value === 'number' - ? parseFloat(value.toFixed(2)) - : value; - - Logger.info(target + ': ' + value, accessory.displayName); - + + value = typeof value === 'number' ? parseFloat(value.toFixed(2)) : value; + + Logger.info(target + ': ' + value, accessory.displayName); + switch (accessory.context.config.subtype) { case 'zone-thermostat': case 'zone-heatercooler': case 'zone-heatercooler-boiler': { - let power, temp, clear; - - let service = accessory.getService(api.hap.Service.HeaterCooler) || accessory.getService(api.hap.Service.Thermostat); - + + let service = + accessory.getService(api.hap.Service.HeaterCooler) || accessory.getService(api.hap.Service.Thermostat); + let targetTempCharacteristic = accessory.getService(api.hap.Service.HeaterCooler) ? api.hap.Characteristic.HeatingThresholdTemperature : api.hap.Characteristic.TargetTemperature; - - if(accessory.context.config.subtype !== 'zone-heatercooler-boiler' && - !accessory.context.config.autoOffDelay && - accessory.context.config.delaySwitch && - accessory.context.delaySwitch && - accessory.context.delayTimer && - value < 5){ - - if(value === 0){ - - if(delayTimer[accessory.displayName]){ + + if ( + accessory.context.config.subtype !== 'zone-heatercooler-boiler' && + !accessory.context.config.autoOffDelay && + accessory.context.config.delaySwitch && + accessory.context.delaySwitch && + accessory.context.delayTimer && + value < 5 + ) { + if (value === 0) { + if (delayTimer[accessory.displayName]) { Logger.info('Resetting delay timer', accessory.displayName); clearTimeout(delayTimer[accessory.displayName]); delayTimer[accessory.displayName] = null; } - + power = 'OFF'; - temp = parseFloat(service - .getCharacteristic(targetTempCharacteristic) - .value.toFixed(2)); - - let mode = accessory.context.config.mode === 'TIMER' - ? (accessory.context.config.modeTimer || 30) * 60 - : accessory.context.config.mode; - - await tado.setZoneOverlay(config.homeId, accessory.context.config.zoneId, power, temp, mode, accessory.context.config.temperatureUnit); - + temp = parseFloat(service.getCharacteristic(targetTempCharacteristic).value.toFixed(2)); + + let mode = + accessory.context.config.mode === 'TIMER' + ? (accessory.context.config.modeTimer || 30) * 60 + : accessory.context.config.mode; + + await tado.setZoneOverlay( + config.homeId, + accessory.context.config.zoneId, + power, + temp, + mode, + accessory.context.config.temperatureUnit + ); } else { - - let mode = accessory.context.config.mode === 'TIMER' - ? (accessory.context.config.modeTimer || 30) * 60 - : accessory.context.config.mode; - + let mode = + accessory.context.config.mode === 'TIMER' + ? (accessory.context.config.modeTimer || 30) * 60 + : accessory.context.config.mode; + let timer = accessory.context.delayTimer; - let tarState = value === 1 - ? 'HEAT' - : 'AUTO'; - - if(delayTimer[accessory.displayName]){ + let tarState = value === 1 ? 'HEAT' : 'AUTO'; + + if (delayTimer[accessory.displayName]) { clearTimeout(delayTimer[accessory.displayName]); delayTimer[accessory.displayName] = null; } - + Logger.info('Wait ' + timer + ' seconds before switching state', accessory.displayName); - + delayTimer[accessory.displayName] = setTimeout(async () => { - Logger.info('Delay timer finished, switching state to ' + tarState, accessory.displayName); - + //targetState clear = value === 3; power = 'ON'; - temp = parseFloat(service - .getCharacteristic(targetTempCharacteristic) - .value.toFixed(2)); - - if(clear || (value && accessory.context.config.mode === 'AUTO' && accessory.context.config.subtype.includes('heatercooler'))){ - await tado.clearZoneOverlay(config.homeId, accessory.context.config.zoneId); + temp = parseFloat(service.getCharacteristic(targetTempCharacteristic).value.toFixed(2)); + + if ( + clear || + (value && + accessory.context.config.mode === 'AUTO' && + accessory.context.config.subtype.includes('heatercooler')) + ) { + await tado.clearZoneOverlay(config.homeId, accessory.context.config.zoneId); return; } - - mode = !value && accessory.context.config.mode === 'AUTO' && accessory.context.config.subtype.includes('heatercooler') - ? 'MANUAL' - : mode; - - await tado.setZoneOverlay(config.homeId, accessory.context.config.zoneId, power, temp, mode, accessory.context.config.temperatureUnit); - + + mode = + !value && + accessory.context.config.mode === 'AUTO' && + accessory.context.config.subtype.includes('heatercooler') + ? 'MANUAL' + : mode; + + await tado.setZoneOverlay( + config.homeId, + accessory.context.config.zoneId, + power, + temp, + mode, + accessory.context.config.temperatureUnit + ); + delayTimer[accessory.displayName] = null; - }, timer * 1000); - } - } else { - - let mode = accessory.context.config.mode === 'TIMER' - ? (accessory.context.config.modeTimer || 30) * 60 - : accessory.context.config.mode; - - if([0,1,3].includes(value)){ - + let mode = + accessory.context.config.mode === 'TIMER' + ? (accessory.context.config.modeTimer || 30) * 60 + : accessory.context.config.mode; + + if ([0, 1, 3].includes(value)) { //targetState clear = value === 3; - - power = value - ? 'ON' - : 'OFF'; - - temp = parseFloat(service - .getCharacteristic(targetTempCharacteristic) - .value.toFixed(2)); - - if(clear || (value && accessory.context.config.mode === 'CUSTOM' && accessory.context.config.subtype.includes('heatercooler'))){ - await tado.clearZoneOverlay(config.homeId, accessory.context.config.zoneId); + + power = value ? 'ON' : 'OFF'; + + temp = parseFloat(service.getCharacteristic(targetTempCharacteristic).value.toFixed(2)); + + if ( + clear || + (value && + accessory.context.config.mode === 'CUSTOM' && + accessory.context.config.subtype.includes('heatercooler')) + ) { + await tado.clearZoneOverlay(config.homeId, accessory.context.config.zoneId); return; } - - mode = !value && accessory.context.config.mode === 'CUSTOM' && accessory.context.config.subtype.includes('heatercooler') - ? 'MANUAL' - : mode; - + + mode = + !value && + accessory.context.config.mode === 'CUSTOM' && + accessory.context.config.subtype.includes('heatercooler') + ? 'MANUAL' + : mode; } else { - //temp power = 'ON'; temp = parseFloat(value.toFixed(2)); - - } - - await tado.setZoneOverlay(config.homeId, accessory.context.config.zoneId, power, temp, mode, accessory.context.config.temperatureUnit); - + } + + await tado.setZoneOverlay( + config.homeId, + accessory.context.config.zoneId, + power, + temp, + mode, + accessory.context.config.temperatureUnit + ); } - break; - - } - + break; + } + case 'zone-switch': case 'zone-faucet': { - let faucetService = accessory.getService(api.hap.Service.Faucet); - + let temp = null; - let power = value - ? 'ON' - : 'OFF'; - - if(faucetService) - faucetService - .getCharacteristic(this.api.hap.Characteristic.InUse) - .updateValue(value); - - let mode = accessory.context.config.mode === 'TIMER' - ? (accessory.context.config.modeTimer || 30) * 60 - : accessory.context.config.mode; - - await tado.setZoneOverlay(config.homeId, accessory.context.config.zoneId, power, temp, mode, accessory.context.config.temperatureUnit); - - break; - - } - + let power = value ? 'ON' : 'OFF'; + + if (faucetService) faucetService.getCharacteristic(this.api.hap.Characteristic.InUse).updateValue(value); + + let mode = + accessory.context.config.mode === 'TIMER' + ? (accessory.context.config.modeTimer || 30) * 60 + : accessory.context.config.mode; + + await tado.setZoneOverlay( + config.homeId, + accessory.context.config.zoneId, + power, + temp, + mode, + accessory.context.config.temperatureUnit + ); + + break; + } + case 'extra-plock': case 'extra-plockswitch': { - let targetState; - - if(accessory.context.config.subtype === 'extra-plockswitch'){ - + + if (accessory.context.config.subtype === 'extra-plockswitch') { let serviceHomeSwitch = accessory.getServiceById(api.hap.Service.Switch, 'HomeSwitch'); let serviceAwaySwitch = accessory.getServiceById(api.hap.Service.Switch, 'AwaySwitch'); - + let characteristic = api.hap.Characteristic.On; - - if(value){ - - if(target === 'Home'){ - + + if (value) { + if (target === 'Home') { targetState = 'HOME'; - - serviceAwaySwitch - .getCharacteristic(characteristic) - .updateValue(false); - + + serviceAwaySwitch.getCharacteristic(characteristic).updateValue(false); } else { - targetState = 'AWAY'; - - serviceHomeSwitch - .getCharacteristic(characteristic) - .updateValue(false); - + + serviceHomeSwitch.getCharacteristic(characteristic).updateValue(false); } - } else { - targetState = 'AUTO'; - - serviceAwaySwitch - .getCharacteristic(characteristic) - .updateValue(false); - - serviceHomeSwitch - .getCharacteristic(characteristic) - .updateValue(false); - + + serviceAwaySwitch.getCharacteristic(characteristic).updateValue(false); + + serviceHomeSwitch.getCharacteristic(characteristic).updateValue(false); } - } else { - let serviceSecurity = accessory.getService(api.hap.Service.SecuritySystem); let characteristicCurrent = api.hap.Characteristic.SecuritySystemCurrentState; - - serviceSecurity - .getCharacteristic(characteristicCurrent) - .updateValue(value); - - if(value === 1){ //away - + + serviceSecurity.getCharacteristic(characteristicCurrent).updateValue(value); + + if (value === 1) { + //away + targetState = 'AWAY'; - - } else if(value === 3){ //off - + } else if (value === 3) { + //off + targetState = 'AUTO'; - - } else { //at home - + } else { + //at home + targetState = 'HOME'; - } - } - + await tado.setPresenceLock(config.homeId, targetState); - break; - - } - + break; + } + case 'zone-window-switch': { - let zoneId = target.split('-'); - zoneId = zoneId[zoneId.length-1]; - + zoneId = zoneId[zoneId.length - 1]; + await tado.setWindowDetection(config.homeId, zoneId, value, 3600); await tado.setOpenWindowMode(config.homeId, zoneId, value); - break; - - } - + break; + } + case 'extra-childswitch': { - await tado.setChildLock(target, value); - break; - + break; } - + case 'extra-cntrlswitch': { - - if(target === 'Dummy') - return; - - const heatAccessories = accessories.filter(acc => acc && acc.context.config.type === 'HEATING'); - - const rooms = accessory.context.config.rooms.map(room => { - return { - id: room.id, - power: target === 'Central' - ? value - ? 'ON' - : 'OFF' - : target === 'Off' - ? 'OFF' - : 'ON', - maxTempInCelsius: target === 'Central' - ? value - ? 25 - : 0 - : target === 'Off' - ? false - : 25, - termination: ['MANUAL', 'AUTO', 'TIMER'].includes(room.mode) - ? room.mode - : 'MANUAL', - timer: ['MANUAL', 'AUTO', 'TIMER'].includes(room.mode) && room.mode === 'TIMER' - ? room.modeTimer && room.modeTimer >= 1 - ? room.modeTimer * 60 - : 1800 //30min - : false - }; - }).filter(room => room); - - if(value){ - - if(target === 'Central'||target === 'Shedule'){ - - const roomIds = accessory.context.config.rooms.map(room => { - return room.id; - }).filter(id => id); - + if (target === 'Dummy') return; + + const heatAccessories = accessories.filter((acc) => acc && acc.context.config.type === 'HEATING'); + + const rooms = accessory.context.config.rooms + .map((room) => { + return { + id: room.id, + power: target === 'Central' ? (value ? 'ON' : 'OFF') : target === 'Off' ? 'OFF' : 'ON', + maxTempInCelsius: target === 'Central' ? (value ? 25 : 0) : target === 'Off' ? false : 25, + termination: ['MANUAL', 'AUTO', 'TIMER'].includes(room.mode) ? room.mode : 'MANUAL', + timer: + ['MANUAL', 'AUTO', 'TIMER'].includes(room.mode) && room.mode === 'TIMER' + ? room.modeTimer && room.modeTimer >= 1 + ? room.modeTimer * 60 + : 1800 //30min + : false, + }; + }) + .filter((room) => room); + + if (value) { + if (target === 'Central' || target === 'Shedule') { + const roomIds = accessory.context.config.rooms + .map((room) => { + return room.id; + }) + .filter((id) => id); + await tado.resumeShedule(config.homeId, roomIds); - + //Turn all back to AUTO/ON - heatAccessories.forEach(acc => { - + heatAccessories.forEach((acc) => { let serviceThermostat = acc.getService(api.hap.Service.Thermostat); - let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler); - - if(serviceThermostat){ - + let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler); + + if (serviceThermostat) { let characteristicTarget = api.hap.Characteristic.TargetHeatingCoolingState; - - serviceThermostat - .getCharacteristic(characteristicTarget) - .updateValue(3); - - } else if(serviceHeaterCooler){ - + + serviceThermostat.getCharacteristic(characteristicTarget).updateValue(3); + } else if (serviceHeaterCooler) { let characteristicActive = api.hap.Characteristic.Active; - - serviceHeaterCooler - .getCharacteristic(characteristicActive) - .updateValue(1); - + + serviceHeaterCooler.getCharacteristic(characteristicActive).updateValue(1); } - }); - + accessory .getServiceById(api.hap.Service.Switch, 'Central') .getCharacteristic(api.hap.Characteristic.On) .updateValue(true); - + return; - } - - if(target === 'Boost'){ - + + if (target === 'Boost') { //Turn On All & Max temp & Central Switch - heatAccessories.forEach(acc => { - + heatAccessories.forEach((acc) => { let serviceThermostat = acc.getService(api.hap.Service.Thermostat); - let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler); - - if(serviceThermostat){ - + let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler); + + if (serviceThermostat) { let characteristicCurrent = api.hap.Characteristic.CurrentHeatingCoolingState; let characteristicTarget = api.hap.Characteristic.TargetHeatingCoolingState; let characteristicTargetTemp = api.hap.Characteristic.TargetTemperature; - + let maxTemp = serviceThermostat.getCharacteristic(characteristicTargetTemp).props.maxValue; - - serviceThermostat - .getCharacteristic(characteristicCurrent) - .updateValue(1); - - serviceThermostat - .getCharacteristic(characteristicTarget) - .updateValue(1); - - serviceThermostat - .getCharacteristic(characteristicTargetTemp) - .updateValue(maxTemp); - - } else if(serviceHeaterCooler){ - + + serviceThermostat.getCharacteristic(characteristicCurrent).updateValue(1); + + serviceThermostat.getCharacteristic(characteristicTarget).updateValue(1); + + serviceThermostat.getCharacteristic(characteristicTargetTemp).updateValue(maxTemp); + } else if (serviceHeaterCooler) { let characteristicActive = api.hap.Characteristic.Active; let characteristicTargetTempHeat = api.hap.Characteristic.HeatingThresholdTemperature; - - let maxTemp = serviceHeaterCooler.getCharacteristic(characteristicTargetTempHeat).props.maxValue; //same for cool - - serviceHeaterCooler - .getCharacteristic(characteristicActive) - .updateValue(1); - - serviceHeaterCooler - .getCharacteristic(characteristicTargetTempHeat) - .updateValue(maxTemp); - + + let maxTemp = serviceHeaterCooler.getCharacteristic(characteristicTargetTempHeat).props.maxValue; //same for cool + + serviceHeaterCooler.getCharacteristic(characteristicActive).updateValue(1); + + serviceHeaterCooler.getCharacteristic(characteristicTargetTempHeat).updateValue(maxTemp); } - }); - + accessory .getServiceById(api.hap.Service.Switch, 'Central') .getCharacteristic(api.hap.Characteristic.On) .updateValue(true); - } - - if(target === 'Off'){ - + + if (target === 'Off') { //Turn Off All && Central Switch - heatAccessories.forEach(acc => { - + heatAccessories.forEach((acc) => { let serviceThermostat = acc.getService(api.hap.Service.Thermostat); - let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler); - - if(serviceThermostat){ - + let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler); + + if (serviceThermostat) { let characteristicCurrent = api.hap.Characteristic.CurrentHeatingCoolingState; let characteristicTarget = api.hap.Characteristic.TargetHeatingCoolingState; - - serviceThermostat - .getCharacteristic(characteristicCurrent) - .updateValue(0); - - serviceThermostat - .getCharacteristic(characteristicTarget) - .updateValue(0); - - } else if(serviceHeaterCooler){ - + + serviceThermostat.getCharacteristic(characteristicCurrent).updateValue(0); + + serviceThermostat.getCharacteristic(characteristicTarget).updateValue(0); + } else if (serviceHeaterCooler) { let characteristicActive = api.hap.Characteristic.Active; - - serviceHeaterCooler - .getCharacteristic(characteristicActive) - .updateValue(0); - + + serviceHeaterCooler.getCharacteristic(characteristicActive).updateValue(0); } - }); - + accessory .getServiceById(api.hap.Service.Switch, 'Central') .getCharacteristic(api.hap.Characteristic.On) .updateValue(false); - } - - if(target !== 'Central'){ + + if (target !== 'Central') { setTimeout(() => { accessory .getServiceById(api.hap.Service.Switch, 'Central' + target) @@ -458,1098 +387,868 @@ module.exports = (api, accessories, config, tado, telegram) => { .updateValue(false); }, 500); } - } else { - - if(target !== 'Central') - return; - + if (target !== 'Central') return; + //Turn Off All && Central Switch - heatAccessories.forEach(acc => { - + heatAccessories.forEach((acc) => { let serviceThermostat = acc.getService(api.hap.Service.Thermostat); - let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler); - - if(serviceThermostat){ - + let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler); + + if (serviceThermostat) { let characteristicCurrent = api.hap.Characteristic.CurrentHeatingCoolingState; let characteristicTarget = api.hap.Characteristic.TargetHeatingCoolingState; - - serviceThermostat - .getCharacteristic(characteristicCurrent) - .updateValue(0); - - serviceThermostat - .getCharacteristic(characteristicTarget) - .updateValue(0); - - } else if(serviceHeaterCooler){ - + + serviceThermostat.getCharacteristic(characteristicCurrent).updateValue(0); + + serviceThermostat.getCharacteristic(characteristicTarget).updateValue(0); + } else if (serviceHeaterCooler) { let characteristicActive = api.hap.Characteristic.Active; - - serviceHeaterCooler - .getCharacteristic(characteristicActive) - .updateValue(0); - + + serviceHeaterCooler.getCharacteristic(characteristicActive).updateValue(0); } - }); - + accessory .getServiceById(api.hap.Service.Switch, 'Central') .getCharacteristic(api.hap.Characteristic.On) .updateValue(false); - } - + await tado.switchAll(config.homeId, rooms); - + break; - } - + default: - Logger.warn('Unknown accessory type! [' + accessory.context.config.subtype + '] ' + target + ': ' + value, accessory.displayName); + Logger.warn( + 'Unknown accessory type! [' + accessory.context.config.subtype + '] ' + target + ': ' + value, + accessory.displayName + ); break; } - - } catch(err) { - + } catch (err) { errorHandler(err); - } finally { - settingState = false; - } - } - - async function changedStates(accessory, historyService, replacer, value){ - - if(value.oldValue !== value.newValue){ - - switch(accessory.context.config.subtype){ - + + async function changedStates(accessory, historyService, replacer, value) { + if (value.oldValue !== value.newValue) { + switch (accessory.context.config.subtype) { case 'zone-thermostat': { - - let currentState = accessory.getService(api.hap.Service.Thermostat).getCharacteristic(api.hap.Characteristic.CurrentHeatingCoolingState).value; - let targetState = accessory.getService(api.hap.Service.Thermostat).getCharacteristic(api.hap.Characteristic.TargetHeatingCoolingState).value; - let currentTemp = accessory.getService(api.hap.Service.Thermostat).getCharacteristic(api.hap.Characteristic.CurrentTemperature).value; - let targetTemp = accessory.getService(api.hap.Service.Thermostat).getCharacteristic(api.hap.Characteristic.TargetTemperature).value; - - let valvePos = currentTemp <= targetTemp && currentState !== api.hap.Characteristic.CurrentHeatingCoolingState.OFF && targetState !== api.hap.Characteristic.TargetHeatingCoolingState.OFF - ? Math.round(((targetTemp - currentTemp) >= 5 ? 100 : (targetTemp - currentTemp) * 20)) - : 0; - - historyService.addEntry({time: moment().unix(), currentTemp: currentTemp, setTemp: targetTemp, valvePosition: valvePos}); - + let currentState = accessory + .getService(api.hap.Service.Thermostat) + .getCharacteristic(api.hap.Characteristic.CurrentHeatingCoolingState).value; + let targetState = accessory + .getService(api.hap.Service.Thermostat) + .getCharacteristic(api.hap.Characteristic.TargetHeatingCoolingState).value; + let currentTemp = accessory + .getService(api.hap.Service.Thermostat) + .getCharacteristic(api.hap.Characteristic.CurrentTemperature).value; + let targetTemp = accessory + .getService(api.hap.Service.Thermostat) + .getCharacteristic(api.hap.Characteristic.TargetTemperature).value; + + let valvePos = + currentTemp <= targetTemp && + currentState !== api.hap.Characteristic.CurrentHeatingCoolingState.OFF && + targetState !== api.hap.Characteristic.TargetHeatingCoolingState.OFF + ? Math.round(targetTemp - currentTemp >= 5 ? 100 : (targetTemp - currentTemp) * 20) + : 0; + + historyService.addEntry({ + time: moment().unix(), + currentTemp: currentTemp, + setTemp: targetTemp, + valvePosition: valvePos, + }); + break; - } - + case 'zone-heatercooler': case 'zone-heatercooler-boiler': { - - let currentState = accessory.getService(api.hap.Service.HeaterCooler).getCharacteristic(api.hap.Characteristic.CurrentHeaterCoolerState).value; - let currentTemp = accessory.getService(api.hap.Service.HeaterCooler).getCharacteristic(api.hap.Characteristic.CurrentTemperature).value; - let targetTemp = accessory.getService(api.hap.Service.HeaterCooler).getCharacteristic(api.hap.Characteristic.HeatingThresholdTemperature).value; - - let valvePos = currentTemp <= targetTemp && currentState !== 0 - ? Math.round(((targetTemp - currentTemp) >= 5 ? 100 : (targetTemp - currentTemp) * 20)) - : 0; - - historyService.addEntry({time: moment().unix(), currentTemp: currentTemp, setTemp: targetTemp, valvePosition: valvePos}); - + let currentState = accessory + .getService(api.hap.Service.HeaterCooler) + .getCharacteristic(api.hap.Characteristic.CurrentHeaterCoolerState).value; + let currentTemp = accessory + .getService(api.hap.Service.HeaterCooler) + .getCharacteristic(api.hap.Characteristic.CurrentTemperature).value; + let targetTemp = accessory + .getService(api.hap.Service.HeaterCooler) + .getCharacteristic(api.hap.Characteristic.HeatingThresholdTemperature).value; + + let valvePos = + currentTemp <= targetTemp && currentState !== 0 + ? Math.round(targetTemp - currentTemp >= 5 ? 100 : (targetTemp - currentTemp) * 20) + : 0; + + historyService.addEntry({ + time: moment().unix(), + currentTemp: currentTemp, + setTemp: targetTemp, + valvePosition: valvePos, + }); + break; - } - + case 'zone-window-contact': { - - if(value.newValue){ - + if (value.newValue) { accessory.context.timesOpened = accessory.context.timesOpened || 0; accessory.context.timesOpened += 1; - + let lastActivation = moment().unix() - historyService.getInitialTime(); let closeDuration = moment().unix() - historyService.getInitialTime(); - + accessory .getService(api.hap.Service.ContactSensor) .getCharacteristic(api.hap.Characteristic.LastActivation) .updateValue(lastActivation); - + accessory .getService(api.hap.Service.ContactSensor) .getCharacteristic(api.hap.Characteristic.TimesOpened) .updateValue(accessory.context.timesOpened); - + accessory .getService(api.hap.Service.ContactSensor) .getCharacteristic(api.hap.Characteristic.ClosedDuration) .updateValue(closeDuration); - } else { - let openDuration = moment().unix() - historyService.getInitialTime(); - + accessory .getService(api.hap.Service.ContactSensor) .getCharacteristic(api.hap.Characteristic.ClosedDuration) .updateValue(openDuration); - } - - historyService.addEntry({time: moment().unix(), status: value.newValue ? 1 : 0}); - - let dest = value.newValue - ? 'opened' - : 'closed'; - + + historyService.addEntry({ time: moment().unix(), status: value.newValue ? 1 : 0 }); + + let dest = value.newValue ? 'opened' : 'closed'; + replacer = replacer.split(accessory.context.config.homeName + ' ')[1]; - let additional = accessory.context.config.homeName; - - if(telegram) - telegram.send('openWindow', dest, replacer, additional); - + let additional = accessory.context.config.homeName; + + if (telegram) telegram.send('openWindow', dest, replacer, additional); + break; - } - + case 'presence-occupancy': case 'presence-motion': { - - if(historyService){ - + if (historyService) { let lastActivation = moment().unix() - historyService.getInitialTime(); - + accessory .getService(api.hap.Service.MotionSensor) .getCharacteristic(api.hap.Characteristic.LastActivation) .updateValue(lastActivation); - - historyService.addEntry({time: moment().unix(), status: value.newValue ? 1 : 0}); - + + historyService.addEntry({ time: moment().unix(), status: value.newValue ? 1 : 0 }); } - - let dest; - + + let dest; + replacer = replacer.split(accessory.context.config.homeName + ' ')[1]; let additional = accessory.context.config.homeName; - - if(value.newValue){ - dest = accessory.displayName === (accessory.context.config.homeName + ' Anyone') - ? 'anyone_in' - : 'user_in'; + + if (value.newValue) { + dest = accessory.displayName === accessory.context.config.homeName + ' Anyone' ? 'anyone_in' : 'user_in'; } else { - dest = accessory.displayName === (accessory.context.config.homeName + ' Anyone') - ? 'anyone_out' - : 'user_out'; - } - - if(telegram) - telegram.send('presence', dest, replacer === 'Anyone' ? false : replacer, additional); - + dest = accessory.displayName === accessory.context.config.homeName + ' Anyone' ? 'anyone_out' : 'user_out'; + } + + if (telegram) telegram.send('presence', dest, replacer === 'Anyone' ? false : replacer, additional); + break; - } - + case 'zone-temperature': case 'weather-temperature': { - - historyService.addEntry({time: moment().unix(), temp: value.newValue, humidity: 0, ppm: 0}); - + historyService.addEntry({ time: moment().unix(), temp: value.newValue, humidity: 0, ppm: 0 }); + break; - } - + case 'zone-humidity': { - - historyService.addEntry({time: moment().unix(), temp: 0, humidity: value.newValue, ppm: 0}); - + historyService.addEntry({ time: moment().unix(), temp: 0, humidity: value.newValue, ppm: 0 }); + break; - } - - default: + + default: Logger.warn('Accessory with unknown subtype wanted to store history data', accessory.displayName); break; - } - } - } - async function getStates(){ - + async function getStates() { try { - //ME - if(!config.homeId) - await updateMe(); - + if (!config.homeId) await updateMe(); + //Home - if(!config.temperatureUnit || (config.extras && config.weather.airQuality && (!config.geolocation || (config.geolocation && !config.geolocation.longitude || !config.geolocation.latitude)))) + if ( + !config.temperatureUnit || + (config.extras && + config.weather.airQuality && + (!config.geolocation || + (config.geolocation && !config.geolocation.longitude) || + !config.geolocation.latitude)) + ) await updateHome(); - - //Zones - if(config.zones.length) - await updateZones(); - + + //Zones + if (config.zones.length) await updateZones(); + //Zones Room Air Quality - if(config.zones.length && config.zones.find(zone => zone && zone.airQuality)) - await updateRoomAirQuality(); - - //MobileDevices - if(config.presence.length) - await updateMobileDevices(); - + if (config.zones.length && config.zones.find((zone) => zone && zone.airQuality)) await updateRoomAirQuality(); + + //MobileDevices + if (config.presence.length) await updateMobileDevices(); + //Weather - if(config.weather.temperatureSensor || config.weather.solarIntensity) - await updateWeather(); - + if (config.weather.temperatureSensor || config.weather.solarIntensity) await updateWeather(); + //AirQuality - if(config.weather.airQuality && config.geolocation && config.geolocation.longitude && config.geolocation.latitude) + if ( + config.weather.airQuality && + config.geolocation && + config.geolocation.longitude && + config.geolocation.latitude + ) await updateAirQuality(); - + //RunningTime - if(config.extras.centralSwitch && config.extras.runningInformation) - await updateRunningTime(); - - //Presence Lock - if(config.extras.presenceLock) - await updatePresence(); - - //Child Lock - if(config.childLock.length) - await updateDevices(); - - } catch(err) { - + if (config.extras.centralSwitch && config.extras.runningInformation) await updateRunningTime(); + + //Presence Lock + if (config.extras.presenceLock) await updatePresence(); + + //Child Lock + if (config.childLock.length) await updateDevices(); + } catch (err) { errorHandler(err); - } finally { - setTimeout(() => { getStates(); }, config.polling * 1000); - } - } - - async function updateMe(){ - - if(!settingState){ - + + async function updateMe() { + if (!settingState) { Logger.debug('Polling User Info...', config.homeName); - + const me = await tado.getMe(); - - if(config.homeName !== me.homes[0].name) - throw ('Cannot find requested home in the API!', config.homeName); - + + if (config.homeName !== me.homes[0].name) throw ('Cannot find requested home in the API!', config.homeName); + config.homeId = me.homes[0].id; - } - + return; - } - - async function updateHome(){ - - if(!settingState){ - - Logger.debug('Polling Home Info...', config.homeName); - + + async function updateHome() { + if (!settingState) { + Logger.debug('Polling Home Info...', config.homeName); + const home = await tado.getHome(config.homeId); - - if(!config.temperatureUnit) - config.temperatureUnit = home.temperatureUnit || 'CELSIUS'; - + + if (!config.temperatureUnit) config.temperatureUnit = home.temperatureUnit || 'CELSIUS'; + //config.skills = home.skills || []; //do we need this? - - if(!config.geolocation || (config.geolocation && !config.geolocation.longitude || !config.geolocation.latitude)){ - - if(!home.geolocation) - home.geolocation = {}; - + + if ( + !config.geolocation || + (config.geolocation && !config.geolocation.longitude) || + !config.geolocation.latitude + ) { + if (!home.geolocation) home.geolocation = {}; + config.geolocation = { longitude: (home.geolocation.longitude || '').toString() || false, - latitude: (home.geolocation.latitude || '').toString() || false + latitude: (home.geolocation.latitude || '').toString() || false, }; - } - } - + return; - } - - async function updateZones(){ - - if(!settingState){ - + + async function updateZones() { + if (!settingState) { Logger.debug('Polling Zones...', config.homeName); - + //CentralSwitch let inManualMode = 0; let inOffMode = 0; let inAutoMode = 0; - - let zonesWithoutID = config.zones.filter(zone => zone && !zone.id); - - if(zonesWithoutID.length){ - - const allZones = await tado.getZones(config.homeId) || []; - - for(const [index, zone] of config.zones.entries()){ - allZones.forEach(zoneWithID => { - if(zoneWithID.name === zone.name) - config.zones[index].id = zoneWithID.id; + + let zonesWithoutID = config.zones.filter((zone) => zone && !zone.id); + + if (zonesWithoutID.length) { + const allZones = (await tado.getZones(config.homeId)) || []; + + for (const [index, zone] of config.zones.entries()) { + allZones.forEach((zoneWithID) => { + if (zoneWithID.name === zone.name) config.zones[index].id = zoneWithID.id; }); } - } - - const allZones = await tado.getZones(config.homeId) || []; - - for(const [index, zone] of config.zones.entries()){ - allZones.forEach(zoneWithID => { - if(zoneWithID.name === zone.name){ - const heatAccessory = accessories.filter(acc => acc && acc.displayName === config.homeName + ' ' + zone.name + ' Heater'); - - if(heatAccessory.length) - heatAccessory[0].context.config.zoneId = zoneWithID.id; - + + const allZones = (await tado.getZones(config.homeId)) || []; + + for (const [index, zone] of config.zones.entries()) { + allZones.forEach((zoneWithID) => { + if (zoneWithID.name === zone.name) { + const heatAccessory = accessories.filter( + (acc) => acc && acc.displayName === config.homeName + ' ' + zone.name + ' Heater' + ); + + if (heatAccessory.length) heatAccessory[0].context.config.zoneId = zoneWithID.id; + config.zones[index].id = zoneWithID.id; config.zones[index].battery = !config.zones[index].noBattery - ? zoneWithID.devices.filter(device => device && zone.type === 'HEATING' && typeof device.batteryState === 'string' && !device.batteryState.includes('NORMAL')).length - ? zoneWithID.devices.filter(device => device && !device.batteryState.includes('NORMAL'))[0].batteryState - : zoneWithID.devices.filter(device => device && device.duties.includes('ZONE_LEADER'))[0].batteryState - : false; - config.zones[index].openWindowEnabled = zoneWithID.openWindowDetection && zoneWithID.openWindowDetection.enabled - ? true + ? zoneWithID.devices.filter( + (device) => + device && + zone.type === 'HEATING' && + typeof device.batteryState === 'string' && + !device.batteryState.includes('NORMAL') + ).length + ? zoneWithID.devices.filter((device) => device && !device.batteryState.includes('NORMAL'))[0] + .batteryState + : zoneWithID.devices.filter((device) => device && device.duties.includes('ZONE_LEADER'))[0].batteryState : false; + config.zones[index].openWindowEnabled = + zoneWithID.openWindowDetection && zoneWithID.openWindowDetection.enabled ? true : false; } }); } - - for(const zone of config.zones){ - + + for (const zone of config.zones) { const zoneState = await tado.getZoneState(config.homeId, zone.id); - + let currentState, targetState, currentTemp, targetTemp, humidity, active, battery, tempEqual; - if(zoneState.setting.type === 'HEATING'){ - - battery = zone.battery === 'NORMAL' - ? 100 - : 10; - - if(zoneState.sensorDataPoints.humidity) - humidity = zoneState.sensorDataPoints.humidity.percentage; - + if (zoneState.setting.type === 'HEATING') { + battery = zone.battery === 'NORMAL' ? 100 : 10; + + if (zoneState.sensorDataPoints.humidity) humidity = zoneState.sensorDataPoints.humidity.percentage; + //HEATING - if(zoneState.sensorDataPoints.insideTemperature){ - - currentTemp = config.temperatureUnit === 'CELSIUS' - ? zoneState.sensorDataPoints.insideTemperature.celsius - : zoneState.sensorDataPoints.insideTemperature.fahrenheit; - - if(zoneState.setting.power === 'ON'){ - - targetTemp = config.temperatureUnit === 'CELSIUS' - ? zoneState.setting.temperature.celsius - : zoneState.setting.temperature.fahrenheit; - + if (zoneState.sensorDataPoints.insideTemperature) { + currentTemp = + config.temperatureUnit === 'FAHRENHEIT' + ? zoneState.sensorDataPoints.insideTemperature.fahrenheit + : zoneState.sensorDataPoints.insideTemperature.celsius; + + if (zoneState.setting.power === 'ON') { + targetTemp = + config.temperatureUnit === 'FAHRENHEIT' + ? zoneState.setting.temperature.fahrenheit + : zoneState.setting.temperature.celsius; + tempEqual = Math.round(currentTemp) === Math.round(targetTemp); - - currentState = currentTemp <= targetTemp - ? 1 - : 2; - - targetState = 1; - + + currentState = currentTemp <= targetTemp ? 1 : 2; + + targetState = 1; + active = 1; - } else { - currentState = 0; targetState = 0; active = 0; - } - - if(zoneState.overlayType === null){ + + if (zoneState.overlayType === null) { currentState = 0; targetState = 3; - } - + } } - + //Thermostat/HeaterCooler - const thermoAccessory = accessories.filter(acc => acc && (acc.context.config.subtype === 'zone-thermostat' || acc.context.config.subtype === 'zone-heatercooler')); - - if(thermoAccessory.length){ - - thermoAccessory.forEach(acc => { - - if(acc.displayName.includes(zone.name)){ - - let serviceThermostat = acc.getService(api.hap.Service.Thermostat); - let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler); - - let serviceBattery = acc.getService(api.hap.Service.BatteryService); + const thermoAccessory = accessories.filter( + (acc) => + acc && + (acc.context.config.subtype === 'zone-thermostat' || acc.context.config.subtype === 'zone-heatercooler') + ); + + if (thermoAccessory.length) { + thermoAccessory.forEach((acc) => { + if (acc.displayName.includes(zone.name)) { + let serviceThermostat = acc.getService(api.hap.Service.Thermostat); + let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler); + + let serviceBattery = acc.getService(api.hap.Service.BatteryService); let characteristicBattery = api.hap.Characteristic.BatteryLevel; - - if(serviceBattery && zone.battery){ - - serviceBattery - .getCharacteristic(characteristicBattery) - .updateValue(battery); - + + if (serviceBattery && zone.battery) { + serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery); } - - if(serviceThermostat){ - + + if (serviceThermostat) { let characteristicCurrentTemp = api.hap.Characteristic.CurrentTemperature; let characteristicTargetTemp = api.hap.Characteristic.TargetTemperature; let characteristicCurrentState = api.hap.Characteristic.CurrentHeatingCoolingState; let characteristicTargetState = api.hap.Characteristic.TargetHeatingCoolingState; - let characteristicHumidity = api.hap.Characteristic.CurrentRelativeHumidity; + let characteristicHumidity = api.hap.Characteristic.CurrentRelativeHumidity; let characteristicUnit = api.hap.Characteristic.TemperatureDisplayUnits; - - if(!isNaN(currentTemp)){ - + + if (!isNaN(currentTemp)) { let tempUnit = serviceThermostat.getCharacteristic(characteristicUnit).value; - - let cToF = (c) => Math.round((c * 9/5) + 32); - let fToC = (f) => Math.round((f - 32) * 5/9); - + + let cToF = (c) => Math.round((c * 9) / 5 + 32); + let fToC = (f) => Math.round(((f - 32) * 5) / 9); + let newValue = tempUnit ? currentTemp <= 25 ? cToF(currentTemp) : currentTemp : currentTemp > 25 - ? fToC(currentTemp) - : currentTemp; - - serviceThermostat - .getCharacteristic(characteristicCurrentTemp) - .updateValue(newValue); - + ? fToC(currentTemp) + : currentTemp; + + serviceThermostat.getCharacteristic(characteristicCurrentTemp).updateValue(newValue); } - - if(!isNaN(targetTemp)) - serviceThermostat - .getCharacteristic(characteristicTargetTemp) - .updateValue(targetTemp); - - if(!isNaN(currentState)) - serviceThermostat - .getCharacteristic(characteristicCurrentState) - .updateValue(currentState); - - if(!isNaN(targetState)) - serviceThermostat - .getCharacteristic(characteristicTargetState) - .updateValue(targetState); - - if(!isNaN(humidity) && serviceThermostat.testCharacteristic(characteristicHumidity)) - serviceThermostat - .getCharacteristic(characteristicHumidity) - .updateValue(humidity); - + + if (!isNaN(targetTemp)) + serviceThermostat.getCharacteristic(characteristicTargetTemp).updateValue(targetTemp); + + if (!isNaN(currentState)) + serviceThermostat.getCharacteristic(characteristicCurrentState).updateValue(currentState); + + if (!isNaN(targetState)) + serviceThermostat.getCharacteristic(characteristicTargetState).updateValue(targetState); + + if (!isNaN(humidity) && serviceThermostat.testCharacteristic(characteristicHumidity)) + serviceThermostat.getCharacteristic(characteristicHumidity).updateValue(humidity); } - - if(serviceHeaterCooler){ - - let characteristicHumidity = api.hap.Characteristic.CurrentRelativeHumidity; + + if (serviceHeaterCooler) { + let characteristicHumidity = api.hap.Characteristic.CurrentRelativeHumidity; let characteristicCurrentTemp = api.hap.Characteristic.CurrentTemperature; let characteristicTargetTempHeating = api.hap.Characteristic.HeatingThresholdTemperature; let characteristicTargetTempCooling = api.hap.Characteristic.CoolingThresholdTemperature; let characteristicCurrentState = api.hap.Characteristic.CurrentHeaterCoolerState; let characteristicTargetState = api.hap.Characteristic.TargetHeaterCoolerState; let characteristicActive = api.hap.Characteristic.Active; - - currentState = active - ? targetState === 3 || tempEqual - ? 1 - : currentState + 1 - : 0; - + + currentState = active ? (targetState === 3 || tempEqual ? 1 : currentState + 1) : 0; + targetState = 1; - - if(!isNaN(active)) - serviceHeaterCooler - .getCharacteristic(characteristicActive) - .updateValue(active); - - if(!isNaN(currentTemp)) - serviceHeaterCooler - .getCharacteristic(characteristicCurrentTemp) - .updateValue(currentTemp); - - if(!isNaN(targetTemp)){ - - serviceHeaterCooler - .getCharacteristic(characteristicTargetTempHeating) - .updateValue(targetTemp); - - serviceHeaterCooler - .getCharacteristic(characteristicTargetTempCooling) - .updateValue(targetTemp); - + + if (!isNaN(active)) serviceHeaterCooler.getCharacteristic(characteristicActive).updateValue(active); + + if (!isNaN(currentTemp)) + serviceHeaterCooler.getCharacteristic(characteristicCurrentTemp).updateValue(currentTemp); + + if (!isNaN(targetTemp)) { + serviceHeaterCooler.getCharacteristic(characteristicTargetTempHeating).updateValue(targetTemp); + + serviceHeaterCooler.getCharacteristic(characteristicTargetTempCooling).updateValue(targetTemp); } - - if(!isNaN(currentState)) - serviceHeaterCooler - .getCharacteristic(characteristicCurrentState) - .updateValue(currentState); - - if(!isNaN(targetState)) - serviceHeaterCooler - .getCharacteristic(characteristicTargetState) - .updateValue(targetState); - - if(!isNaN(humidity) && serviceHeaterCooler.testCharacteristic(characteristicHumidity)) - serviceHeaterCooler - .getCharacteristic(characteristicHumidity) - .updateValue(humidity); - + + if (!isNaN(currentState)) + serviceHeaterCooler.getCharacteristic(characteristicCurrentState).updateValue(currentState); + + if (!isNaN(targetState)) + serviceHeaterCooler.getCharacteristic(characteristicTargetState).updateValue(targetState); + + if (!isNaN(humidity) && serviceHeaterCooler.testCharacteristic(characteristicHumidity)) + serviceHeaterCooler.getCharacteristic(characteristicHumidity).updateValue(humidity); } - } - }); - } - - } else { - - if(zoneState.setting.power === 'ON'){ - + } else { + if (zoneState.setting.power === 'ON') { active = 1; - currentState = zoneState.overlayType === null - ? 1 - : 2; - + currentState = zoneState.overlayType === null ? 1 : 2; } else { - active = 0; currentState = 0; - } - + targetState = 1; - - currentTemp = zoneState.setting.temperature !== null - ? config.temperatureUnit === 'CELSIUS' - ? zoneState.setting.temperature.celsius - : zoneState.setting.temperature.fahrenheit - : undefined; - - targetTemp = active && currentTemp - ? currentTemp - : undefined; - + + currentTemp = + zoneState.setting.temperature !== null + ? config.temperatureUnit === 'FAHRENHEIT' + ? zoneState.setting.temperature.fahrenheit + : zoneState.setting.temperature.celsius + : undefined; + + targetTemp = active && currentTemp ? currentTemp : undefined; + //Thermostat/HeaterCooler - const heaterAccessory = accessories.filter(acc => acc && acc.context.config.subtype === 'zone-heatercooler-boiler'); - const switchAccessory = accessories.filter(acc => acc && acc.context.config.subtype === 'zone-switch'); - const faucetAccessory = accessories.filter(acc => acc && acc.context.config.subtype === 'zone-faucet'); - - if(heaterAccessory.length){ - - heaterAccessory.forEach(acc => { - - if(acc.displayName.includes(zone.name)){ - - let service = acc.getService(api.hap.Service.HeaterCooler); - + const heaterAccessory = accessories.filter( + (acc) => acc && acc.context.config.subtype === 'zone-heatercooler-boiler' + ); + const switchAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-switch'); + const faucetAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-faucet'); + + if (heaterAccessory.length) { + heaterAccessory.forEach((acc) => { + if (acc.displayName.includes(zone.name)) { + let service = acc.getService(api.hap.Service.HeaterCooler); + let characteristicCurrentTemp = api.hap.Characteristic.CurrentTemperature; let characteristicActive = api.hap.Characteristic.Active; let characteristicCurrentState = api.hap.Characteristic.CurrentHeaterCoolerState; let characteristicTargetState = api.hap.Characteristic.TargetHeaterCoolerState; let characteristicTargetTempHeating = api.hap.Characteristic.HeatingThresholdTemperature; - service - .getCharacteristic(characteristicActive) - .updateValue(active); - - service - .getCharacteristic(characteristicCurrentState) - .updateValue(currentState); - - service - .getCharacteristic(characteristicTargetState) - .updateValue(targetState); - - if(!isNaN(currentTemp) || acc.context.currentTemp){ - - if(!isNaN(currentTemp)) - acc.context.currentTemp = currentTemp; //store current temp in config - - service - .getCharacteristic(characteristicCurrentTemp) - .updateValue(acc.context.currentTemp); - + service.getCharacteristic(characteristicActive).updateValue(active); + + service.getCharacteristic(characteristicCurrentState).updateValue(currentState); + + service.getCharacteristic(characteristicTargetState).updateValue(targetState); + + if (!isNaN(currentTemp) || acc.context.currentTemp) { + if (!isNaN(currentTemp)) acc.context.currentTemp = currentTemp; //store current temp in config + + service.getCharacteristic(characteristicCurrentTemp).updateValue(acc.context.currentTemp); } - - if(!isNaN(targetTemp)){ - - service - .getCharacteristic(characteristicTargetTempHeating) - .updateValue(targetTemp); - + + if (!isNaN(targetTemp)) { + service.getCharacteristic(characteristicTargetTempHeating).updateValue(targetTemp); } - } - }); - } - - if(switchAccessory.length){ - - switchAccessory.forEach(acc => { - - if(acc.displayName.includes(zone.name)){ - + + if (switchAccessory.length) { + switchAccessory.forEach((acc) => { + if (acc.displayName.includes(zone.name)) { let service = acc.getService(api.hap.Service.Switch); - + let characteristic = api.hap.Characteristic.On; - - service - .getCharacteristic(characteristic) - .updateValue(active ? true : false); - + + service.getCharacteristic(characteristic).updateValue(active ? true : false); } - }); - } - - if(faucetAccessory.length){ - - faucetAccessory.forEach(acc => { - - if(acc.displayName.includes(zone.name)){ - + + if (faucetAccessory.length) { + faucetAccessory.forEach((acc) => { + if (acc.displayName.includes(zone.name)) { let service = acc.getService(api.hap.Service.Valve); - + let characteristicActive = api.hap.Characteristic.Active; let characteristicInUse = api.hap.Characteristic.InUse; - - service - .getCharacteristic(characteristicActive) - .updateValue(active ? 1 : 0); - - service - .getCharacteristic(characteristicInUse) - .updateValue(active ? 1 : 0); - - + + service.getCharacteristic(characteristicActive).updateValue(active ? 1 : 0); + + service.getCharacteristic(characteristicInUse).updateValue(active ? 1 : 0); } - }); - } - } - + //TemperatureSensor - const tempAccessory = accessories.filter(acc => acc && acc.context.config.subtype === 'zone-temperature'); - - if(tempAccessory.length){ - - tempAccessory.forEach(acc => { - - if(acc.displayName.includes(zone.name)){ - - let serviceBattery = acc.getService(api.hap.Service.BatteryService); + const tempAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-temperature'); + + if (tempAccessory.length) { + tempAccessory.forEach((acc) => { + if (acc.displayName.includes(zone.name)) { + let serviceBattery = acc.getService(api.hap.Service.BatteryService); let characteristicBattery = api.hap.Characteristic.BatteryLevel; - - if(serviceBattery && !isNaN(battery)){ - - serviceBattery - .getCharacteristic(characteristicBattery) - .updateValue(battery); - + + if (serviceBattery && !isNaN(battery)) { + serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery); } - - if(!isNaN(currentTemp)){ - - let service = acc.getService(api.hap.Service.TemperatureSensor); + + if (!isNaN(currentTemp)) { + let service = acc.getService(api.hap.Service.TemperatureSensor); let characteristic = api.hap.Characteristic.CurrentTemperature; - - service - .getCharacteristic(characteristic) - .updateValue(currentTemp); - + + service.getCharacteristic(characteristic).updateValue(currentTemp); } - } - }); - } - + //HumiditySensor - const humidityAccessory = accessories.filter(acc => acc && acc.context.config.subtype === 'zone-humidity'); - - humidityAccessory.forEach(acc => { - - if(acc.displayName.includes(zone.name)){ - - let serviceBattery = acc.getService(api.hap.Service.BatteryService); + const humidityAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-humidity'); + + humidityAccessory.forEach((acc) => { + if (acc.displayName.includes(zone.name)) { + let serviceBattery = acc.getService(api.hap.Service.BatteryService); let characteristicBattery = api.hap.Characteristic.BatteryLevel; - - if(serviceBattery && !isNaN(battery)){ - - serviceBattery - .getCharacteristic(characteristicBattery) - .updateValue(battery); - + + if (serviceBattery && !isNaN(battery)) { + serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery); } - - if(!isNaN(humidity)){ - - let service = acc.getService(api.hap.Service.HumiditySensor); + + if (!isNaN(humidity)) { + let service = acc.getService(api.hap.Service.HumiditySensor); let characteristic = api.hap.Characteristic.CurrentRelativeHumidity; - - service - .getCharacteristic(characteristic) - .updateValue(humidity); - + + service.getCharacteristic(characteristic).updateValue(humidity); } - } - }); - + //WindowSensor - const windowContactAccessory = accessories.filter(acc => acc && acc.context.config.subtype === 'zone-window-contact'); - const windowSwitchAccessory = accessories.filter(acc => acc && acc.displayName === acc.context.config.homeName + ' Open Window'); - - if(windowContactAccessory.length){ - - windowContactAccessory.forEach(acc => { - - if(acc.displayName.includes(zone.name)){ - - let serviceBattery = acc.getService(api.hap.Service.BatteryService); + const windowContactAccessory = accessories.filter( + (acc) => acc && acc.context.config.subtype === 'zone-window-contact' + ); + const windowSwitchAccessory = accessories.filter( + (acc) => acc && acc.displayName === acc.context.config.homeName + ' Open Window' + ); + + if (windowContactAccessory.length) { + windowContactAccessory.forEach((acc) => { + if (acc.displayName.includes(zone.name)) { + let serviceBattery = acc.getService(api.hap.Service.BatteryService); let characteristicBattery = api.hap.Characteristic.BatteryLevel; - - if(serviceBattery && !isNaN(battery)){ - - serviceBattery - .getCharacteristic(characteristicBattery) - .updateValue(battery); - + + if (serviceBattery && !isNaN(battery)) { + serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery); } - + let service = acc.getService(api.hap.Service.ContactSensor); let characteristic = api.hap.Characteristic.ContactSensorState; - - let state = zoneState.openWindow || zoneState.openWindowDetected - ? 1 - : 0; - - service - .getCharacteristic(characteristic) - .updateValue(state); - + + let state = zoneState.openWindow || zoneState.openWindowDetected ? 1 : 0; + + service.getCharacteristic(characteristic).updateValue(state); } - }); - } - - if(windowSwitchAccessory.length){ - - windowSwitchAccessory[0].services.forEach(switchService => { - - if(switchService.subtype && switchService.subtype.includes(zone.name)){ - - let service = windowSwitchAccessory[0].getServiceById(api.hap.Service.Switch, switchService.subtype); + + if (windowSwitchAccessory.length) { + windowSwitchAccessory[0].services.forEach((switchService) => { + if (switchService.subtype && switchService.subtype.includes(zone.name)) { + let service = windowSwitchAccessory[0].getServiceById(api.hap.Service.Switch, switchService.subtype); let characteristic = api.hap.Characteristic.On; - - let state = zone.openWindowEnabled - ? true - : false; - - service - .getCharacteristic(characteristic) - .updateValue(state); - + + let state = zone.openWindowEnabled ? true : false; + + service.getCharacteristic(characteristic).updateValue(state); } - }); - } - - if(zoneState.setting.type === 'HEATING'){ - + + if (zoneState.setting.type === 'HEATING') { //CentralSwitch - if(zoneState.overlayType === null) - inAutoMode += 1; - - if(zoneState.overlayType !== null && zoneState.setting.power === 'OFF') - inOffMode += 1; - - if(zoneState.overlayType !== null && zoneState.setting.power === 'ON' && zoneState.overlay.termination) + if (zoneState.overlayType === null) inAutoMode += 1; + + if (zoneState.overlayType !== null && zoneState.setting.power === 'OFF') inOffMode += 1; + + if (zoneState.overlayType !== null && zoneState.setting.power === 'ON' && zoneState.overlay.termination) inManualMode += 1; - } - } - + //CentralSwitch - const centralSwitchAccessory = accessories.filter(acc => acc && acc.displayName === acc.context.config.homeName + ' Central Switch'); - - if(centralSwitchAccessory.length){ - - centralSwitchAccessory[0].services.forEach(service => { - - if(service.subtype === 'Central'){ - + const centralSwitchAccessory = accessories.filter( + (acc) => acc && acc.displayName === acc.context.config.homeName + ' Central Switch' + ); + + if (centralSwitchAccessory.length) { + centralSwitchAccessory[0].services.forEach((service) => { + if (service.subtype === 'Central') { let serviceSwitch = centralSwitchAccessory[0].getServiceById(api.hap.Service.Switch, service.subtype); let characteristicOn = api.hap.Characteristic.On; let characteristicAuto = api.hap.Characteristic.AutoThermostats; let characteristicOff = api.hap.Characteristic.OfflineThermostats; let characteristicManual = api.hap.Characteristic.ManualThermostats; - + let state = (inManualMode || inAutoMode) !== 0; - - serviceSwitch - .getCharacteristic(characteristicAuto) - .updateValue(inAutoMode); - - serviceSwitch - .getCharacteristic(characteristicManual) - .updateValue(inManualMode); - - serviceSwitch - .getCharacteristic(characteristicOff) - .updateValue(inOffMode); - - serviceSwitch - .getCharacteristic(characteristicOn) - .updateValue(state); - + + serviceSwitch.getCharacteristic(characteristicAuto).updateValue(inAutoMode); + + serviceSwitch.getCharacteristic(characteristicManual).updateValue(inManualMode); + + serviceSwitch.getCharacteristic(characteristicOff).updateValue(inOffMode); + + serviceSwitch.getCharacteristic(characteristicOn).updateValue(state); } - }); - } - } - } - - async function updateMobileDevices(){ - - if(!settingState){ - - Logger.debug('Polling MobileDevices...', config.homeName); - + + async function updateMobileDevices() { + if (!settingState) { + Logger.debug('Polling MobileDevices...', config.homeName); + const mobileDevices = await tado.getMobileDevices(config.homeId); - - const userAccessories = accessories.filter(user => user && user.context.config.subtype.includes('presence') && user.displayName !== user.context.config.homeName + ' Anyone'); - - const anyone = accessories.filter(user => user && user.context.config.subtype.includes('presence') && user.displayName === user.context.config.homeName + ' Anyone'); - + + const userAccessories = accessories.filter( + (user) => + user && + user.context.config.subtype.includes('presence') && + user.displayName !== user.context.config.homeName + ' Anyone' + ); + + const anyone = accessories.filter( + (user) => + user && + user.context.config.subtype.includes('presence') && + user.displayName === user.context.config.homeName + ' Anyone' + ); + let activeUser = 0; - - mobileDevices.forEach(device => { - userAccessories.forEach(acc => { - if((acc.context.config.homeName + ' ' + device.name) === acc.displayName){ - - let atHome = device.location && device.location.atHome - ? 1 - : 0; - - if(atHome) - activeUser += 1; - - let service = acc.getService(api.hap.Service.MotionSensor) || acc.getService(api.hap.Service.OccupancySensor); - + + mobileDevices.forEach((device) => { + userAccessories.forEach((acc) => { + if (acc.context.config.homeName + ' ' + device.name === acc.displayName) { + let atHome = device.location && device.location.atHome ? 1 : 0; + + if (atHome) activeUser += 1; + + let service = + acc.getService(api.hap.Service.MotionSensor) || acc.getService(api.hap.Service.OccupancySensor); + let characteristic = service.testCharacteristic(api.hap.Characteristic.MotionDetected) ? api.hap.Characteristic.MotionDetected : api.hap.Characteristic.OccupancyDetected; - - service - .getCharacteristic(characteristic) - .updateValue(atHome); + service.getCharacteristic(characteristic).updateValue(atHome); } }); }); - - if(anyone.length){ - - let service = anyone[0].getService(api.hap.Service.MotionSensor) || anyone[0].getService(api.hap.Service.OccupancySensor); - + + if (anyone.length) { + let service = + anyone[0].getService(api.hap.Service.MotionSensor) || anyone[0].getService(api.hap.Service.OccupancySensor); + let characteristic = service.testCharacteristic(api.hap.Characteristic.MotionDetected) ? api.hap.Characteristic.MotionDetected : api.hap.Characteristic.OccupancyDetected; - - service - .getCharacteristic(characteristic) - .updateValue(activeUser ? 1 : 0); - + + service.getCharacteristic(characteristic).updateValue(activeUser ? 1 : 0); } - } - - return; - + + return; } - - async function updateWeather(){ - - if(!settingState){ - - const weatherTemperatureAccessory = accessories.filter(acc => acc && acc.displayName === acc.context.config.homeName + ' Weather'); - - const solarIntensityAccessory = accessories.filter(acc => acc && acc.displayName === acc.context.config.homeName + ' Solar Intensity'); - - if(weatherTemperatureAccessory.length || solarIntensityAccessory.length){ - - Logger.debug('Polling Weather...', config.homeName); - + + async function updateWeather() { + if (!settingState) { + const weatherTemperatureAccessory = accessories.filter( + (acc) => acc && acc.displayName === acc.context.config.homeName + ' Weather' + ); + + const solarIntensityAccessory = accessories.filter( + (acc) => acc && acc.displayName === acc.context.config.homeName + ' Solar Intensity' + ); + + if (weatherTemperatureAccessory.length || solarIntensityAccessory.length) { + Logger.debug('Polling Weather...', config.homeName); + const weather = await tado.getWeather(config.homeId); - - if(weatherTemperatureAccessory.length && weather.outsideTemperature){ - + + if (weatherTemperatureAccessory.length && weather.outsideTemperature) { let tempUnit = config.temperatureUnit; - let service = weatherTemperatureAccessory[0].getService(api.hap.Service.TemperatureSensor); + let service = weatherTemperatureAccessory[0].getService(api.hap.Service.TemperatureSensor); let characteristic = api.hap.Characteristic.CurrentTemperature; - - let temp = tempUnit === 'FAHRENHEIT' - ? weather.outsideTemperature.fahrenheit - : weather.outsideTemperature.celsius; - - service - .getCharacteristic(characteristic) - .updateValue(temp); - + + let temp = + tempUnit === 'FAHRENHEIT' ? weather.outsideTemperature.fahrenheit : weather.outsideTemperature.celsius; + + service.getCharacteristic(characteristic).updateValue(temp); } - - if(solarIntensityAccessory.length && weather.solarIntensity){ - + + if (solarIntensityAccessory.length && weather.solarIntensity) { let state = weather.solarIntensity.percentage !== 0; let brightness = weather.solarIntensity.percentage; - + solarIntensityAccessory[0].context.lightBulbState = state; solarIntensityAccessory[0].context.lightBulbBrightness = brightness; - - let serviceLightbulb = solarIntensityAccessory[0].getService(api.hap.Service.Lightbulb); - let serviceLightsensor = solarIntensityAccessory[0].getService(api.hap.Service.LightSensor); - - if(serviceLightbulb){ - + + let serviceLightbulb = solarIntensityAccessory[0].getService(api.hap.Service.Lightbulb); + let serviceLightsensor = solarIntensityAccessory[0].getService(api.hap.Service.LightSensor); + + if (serviceLightbulb) { let characteristicOn = api.hap.Characteristic.On; let characteristicBrightness = api.hap.Characteristic.Brightness; - - serviceLightbulb - .getCharacteristic(characteristicOn) - .updateValue(state); - - serviceLightbulb - .getCharacteristic(characteristicBrightness) - .updateValue(brightness); - + + serviceLightbulb.getCharacteristic(characteristicOn).updateValue(state); + + serviceLightbulb.getCharacteristic(characteristicBrightness).updateValue(brightness); } else { - let characteristicLux = api.hap.Characteristic.CurrentAmbientLightLevel; - + serviceLightsensor .getCharacteristic(characteristicLux) - .updateValue(brightness - ? brightness * 1000 - : 0.0001); - + .updateValue(brightness ? brightness * 1000 : 0.0001); } - - } - + } } - } - + return; - } - - async function updateRoomAirQuality(){ - - if(!settingState){ - + + async function updateRoomAirQuality() { + if (!settingState) { Logger.debug('Polling Room AirQuality...', config.homeName); - + const airQuality = await tado.getAirComfort(config.homeId); - - const heatAccessories = accessories.filter(acc => acc && acc.context.config.subtype === 'zone-thermostat' || acc.context.config.subtype === 'zone-heatercooler'); - - heatAccessories.forEach(acc => { - - if(acc.context.config.airQuality){ - - airQuality.comfort.forEach(room => { - - if(room.roomId === acc.context.config.zoneId && room.coordinate){ - - let state = room.coordinate.radial >= 0.8 - ? 5 - : room.coordinate.radial >= 0.6 + + const heatAccessories = accessories.filter( + (acc) => + (acc && acc.context.config.subtype === 'zone-thermostat') || + acc.context.config.subtype === 'zone-heatercooler' + ); + + heatAccessories.forEach((acc) => { + if (acc.context.config.airQuality) { + airQuality.comfort.forEach((room) => { + if (room.roomId === acc.context.config.zoneId && room.coordinate) { + let state = + room.coordinate.radial >= 0.8 + ? 5 + : room.coordinate.radial >= 0.6 ? 4 : room.coordinate.radial >= 0.4 - ? 3 - : room.coordinate.radial >= 0.2 - ? 2 - : room.coordinate.radial >= 0 - ? 1 - : 0; - + ? 3 + : room.coordinate.radial >= 0.2 + ? 2 + : room.coordinate.radial >= 0 + ? 1 + : 0; + let service = acc.getService(api.hap.Service.Thermostat) || acc.getService(api.hap.Service.HeaterCooler); let characteristic = api.hap.Characteristic.AirQuality; - - service - .getCharacteristic(characteristic) - .updateValue(state); - + + service.getCharacteristic(characteristic).updateValue(state); } - }); - } - }); - } - } - - async function updateAirQuality(){ - - if(!settingState){ - - const airQualityAccessory = accessories.filter(acc => acc && acc.displayName === acc.context.config.homeName + ' Air Quality'); - - if(airQualityAccessory.length){ - + + async function updateAirQuality() { + if (!settingState) { + const airQualityAccessory = accessories.filter( + (acc) => acc && acc.displayName === acc.context.config.homeName + ' Air Quality' + ); + + if (airQualityAccessory.length) { Logger.debug('Polling AirQuality...', config.homeName); - - const airQuality = await tado.getWeatherAirComfort(config.homeId, config.geolocation.longitude, config.geolocation.latitude); - - let service = airQualityAccessory[0].getService(api.hap.Service.AirQualitySensor); - + + const airQuality = await tado.getWeatherAirComfort( + config.homeId, + config.geolocation.longitude, + config.geolocation.latitude + ); + + let service = airQualityAccessory[0].getService(api.hap.Service.AirQualitySensor); + let characteristicAqi = api.hap.Characteristic.AirQuality; let characteristicPm10 = api.hap.Characteristic.PM10Density; let characteristicPm25 = api.hap.Characteristic.PM2_5Density; @@ -1557,292 +1256,215 @@ module.exports = (api, accessories, config, tado, telegram) => { let characteristicOd = api.hap.Characteristic.OzoneDensity; let characteristicSdd = api.hap.Characteristic.SulphurDioxideDensity; let characteristicCo = api.hap.Characteristic.CarbonMonoxideLevel; - - if(airQuality.outdoorQuality){ - - let returnPol = (target) => airQuality.outdoorQuality.pollutants.filter(pol => pol && pol.scientificName.includes(target)); - - let aqi = airQuality.outdoorQuality.aqi.value >= 80 - ? 1 - : airQuality.outdoorQuality.aqi.value >= 60 + + if (airQuality.outdoorQuality) { + let returnPol = (target) => + airQuality.outdoorQuality.pollutants.filter((pol) => pol && pol.scientificName.includes(target)); + + let aqi = + airQuality.outdoorQuality.aqi.value >= 80 + ? 1 + : airQuality.outdoorQuality.aqi.value >= 60 ? 2 : airQuality.outdoorQuality.aqi.value >= 40 - ? 3 - : airQuality.outdoorQuality.aqi.value >= 20 - ? 4 - : airQuality.outdoorQuality.aqi.value >= 0 - ? 5 - : 0; - + ? 3 + : airQuality.outdoorQuality.aqi.value >= 20 + ? 4 + : airQuality.outdoorQuality.aqi.value >= 0 + ? 5 + : 0; + let pm10 = returnPol('PM10')[0].concentration.value; let pm25 = returnPol('PM2.5')[0].concentration.value; let ndd = returnPol('NO2')[0].concentration.value; let od = returnPol('O3')[0].concentration.value; let sdd = returnPol('SO2')[0].concentration.value; let co = returnPol('CO')[0].concentration.value; - - if(!isNaN(aqi)) - service - .getCharacteristic(characteristicAqi) - .updateValue(aqi); - - if(!isNaN(pm10)) - service - .getCharacteristic(characteristicPm10) - .updateValue(pm10); - - if(!isNaN(pm25)) - service - .getCharacteristic(characteristicPm25) - .updateValue(pm25); - - if(!isNaN(ndd)) - service - .getCharacteristic(characteristicNdd) - .updateValue(ndd * 1.9123); - - if(!isNaN(od)) - service - .getCharacteristic(characteristicOd) - .updateValue(od * 1.9954); - - if(!isNaN(sdd)) - service - .getCharacteristic(characteristicSdd) - .updateValue(sdd * 2.6647); - - if(!isNaN(co)) - service - .getCharacteristic(characteristicCo) - .updateValue(co / 1000); //ppb to ppm - + + if (!isNaN(aqi)) service.getCharacteristic(characteristicAqi).updateValue(aqi); + + if (!isNaN(pm10)) service.getCharacteristic(characteristicPm10).updateValue(pm10); + + if (!isNaN(pm25)) service.getCharacteristic(characteristicPm25).updateValue(pm25); + + if (!isNaN(ndd)) service.getCharacteristic(characteristicNdd).updateValue(ndd * 1.9123); + + if (!isNaN(od)) service.getCharacteristic(characteristicOd).updateValue(od * 1.9954); + + if (!isNaN(sdd)) service.getCharacteristic(characteristicSdd).updateValue(sdd * 2.6647); + + if (!isNaN(co)) service.getCharacteristic(characteristicCo).updateValue(co / 1000); //ppb to ppm } - } - } - + return; - } - - async function updatePresence(){ - - if(!settingState){ - - const presenceLockAccessory = accessories.filter(acc => acc && acc.displayName === acc.context.config.homeName + ' Presence Lock'); - - if(presenceLockAccessory.length){ - + + async function updatePresence() { + if (!settingState) { + const presenceLockAccessory = accessories.filter( + (acc) => acc && acc.displayName === acc.context.config.homeName + ' Presence Lock' + ); + + if (presenceLockAccessory.length) { Logger.debug('Polling PresenceLock...', config.homeName); - + const presenceLock = await tado.getState(config.homeId); - + /* 0: Home | true 1: Away | true 3: Off | false */ - - let state = presenceLock.presenceLocked - ? presenceLock.presence === 'AWAY' - ? 1 - : 0 - : 3; - - let serviceSecurity = presenceLockAccessory[0].getService(api.hap.Service.SecuritySystem); + + let state = presenceLock.presenceLocked ? (presenceLock.presence === 'AWAY' ? 1 : 0) : 3; + + let serviceSecurity = presenceLockAccessory[0].getService(api.hap.Service.SecuritySystem); let serviceHomeSwitch = presenceLockAccessory[0].getServiceById(api.hap.Service.Switch, 'HomeSwitch'); - let serviceAwaySwitch = presenceLockAccessory[0].getServiceById(api.hap.Service.Switch, 'AwaySwitch'); - - if(serviceSecurity){ - + let serviceAwaySwitch = presenceLockAccessory[0].getServiceById(api.hap.Service.Switch, 'AwaySwitch'); + + if (serviceSecurity) { let characteristicCurrent = api.hap.Characteristic.SecuritySystemCurrentState; let characteristicTarget = api.hap.Characteristic.SecuritySystemTargetState; - - serviceSecurity - .getCharacteristic(characteristicCurrent) - .updateValue(state); - - serviceSecurity - .getCharacteristic(characteristicTarget) - .updateValue(state); - - } else if(serviceHomeSwitch || serviceAwaySwitch){ - + + serviceSecurity.getCharacteristic(characteristicCurrent).updateValue(state); + + serviceSecurity.getCharacteristic(characteristicTarget).updateValue(state); + } else if (serviceHomeSwitch || serviceAwaySwitch) { let characteristicOn = api.hap.Characteristic.On; - - let homeState = !state - ? true - : false; - - let awayState = state === 1 - ? true - : false; - - serviceAwaySwitch - .getCharacteristic(characteristicOn) - .updateValue(awayState); - - serviceHomeSwitch - .getCharacteristic(characteristicOn) - .updateValue(homeState); - + + let homeState = !state ? true : false; + + let awayState = state === 1 ? true : false; + + serviceAwaySwitch.getCharacteristic(characteristicOn).updateValue(awayState); + + serviceHomeSwitch.getCharacteristic(characteristicOn).updateValue(homeState); } - } - } - } - - async function updateRunningTime(){ - - if(!settingState){ - - const centralSwitchAccessory = accessories.filter(acc => acc && acc.displayName === acc.context.config.homeName + ' Central Switch'); - - if(centralSwitchAccessory.length){ - + + async function updateRunningTime() { + if (!settingState) { + const centralSwitchAccessory = accessories.filter( + (acc) => acc && acc.displayName === acc.context.config.homeName + ' Central Switch' + ); + + if (centralSwitchAccessory.length) { Logger.debug('Polling RunningTime...', config.homeName); - + let periods = ['days', 'months', 'years']; - - for(const period of periods){ - - let fromDate = period === 'days' - ? moment().format('YYYY-MM-DD') - : period === 'months' + + for (const period of periods) { + let fromDate = + period === 'days' + ? moment().format('YYYY-MM-DD') + : period === 'months' ? moment().subtract(1, 'days').subtract(1, period).format('YYYY-MM-DD') : moment().add(1, 'months').startOf('month').subtract(1, period).format('YYYY-MM-DD'); - - - let toDate = period === 'years' - ? moment().format('YYYY-MM-DD') - : false; - + + let toDate = period === 'years' ? moment().format('YYYY-MM-DD') : false; + let time = period.substring(0, period.length - 1); - + const runningTime = await tado.getRunningTime(config.homeId, time, fromDate, toDate); - - if(runningTime && runningTime.summary){ - + + if (runningTime && runningTime.summary) { let summaryInHours = runningTime.summary.totalRunningTimeInSeconds / 3600; - - let serviceSwitch = centralSwitchAccessory[0].getServiceById(api.hap.Service.Switch, 'Central'); - let characteristic = period === 'years' - ? api.hap.Characteristic.OverallHeatYear - : period === 'months' + + let serviceSwitch = centralSwitchAccessory[0].getServiceById(api.hap.Service.Switch, 'Central'); + let characteristic = + period === 'years' + ? api.hap.Characteristic.OverallHeatYear + : period === 'months' ? api.hap.Characteristic.OverallHeatMonth : api.hap.Characteristic.OverallHeatDay; - - serviceSwitch - .getCharacteristic(characteristic) - .updateValue(summaryInHours); - + + serviceSwitch.getCharacteristic(characteristic).updateValue(summaryInHours); } - + await timeout(500); - } - } - } - + return; - } - - async function updateDevices(){ - - if(!settingState){ - + + async function updateDevices() { + if (!settingState) { Logger.debug('Polling Devices...', config.homeName); - + const devices = await tado.getDevices(config.homeId); - - const childLockAccessories = accessories.filter(acc => acc && acc.context.config.subtype === 'extra-childswitch'); - - devices.forEach(device => { - childLockAccessories[0].services.forEach(service => { - if(device.serialNo === service.subtype){ - + + const childLockAccessories = accessories.filter( + (acc) => acc && acc.context.config.subtype === 'extra-childswitch' + ); + + devices.forEach((device) => { + childLockAccessories[0].services.forEach((service) => { + if (device.serialNo === service.subtype) { let serviceChildLock = childLockAccessories[0].getServiceById(api.hap.Service.Switch, service.subtype); let characteristic = api.hap.Characteristic.On; - + let childLockEnabled = device.childLockEnabled || false; - - serviceChildLock - .getCharacteristic(characteristic) - .updateValue(childLockEnabled); + serviceChildLock.getCharacteristic(characteristic).updateValue(childLockEnabled); } }); }); - } - + return; - } - + function errorHandler(err) { - let error; - - if(err.options) - Logger.debug('API request ' + err.options.method + ' ' + err.options.url.pathname + ' ' + err.message, config.homeName); - - if(err.response){ + if (err.options) + Logger.debug( + 'API request ' + err.options.method + ' ' + err.options.url.pathname + ' ' + err.message, + config.homeName + ); + + if (err.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx - if(err.response.data){ - + if (err.response.data) { error = { status: err.response.status, message: err.response.statusText, - data: err.response.data + data: err.response.data, }; - } else { - error = { status: err.response.status, - message: err.response.statusText + message: err.response.statusText, }; - } - - } else if(err.request){ - + } else if (err.request) { error = { code: err.code, - message: 'Cannot reach Tado. No response received.' + message: 'Cannot reach Tado. No response received.', }; - - } else if(err.output && err.output.payload && Object.keys(err.output.payload).length) { - + } else if (err.output && err.output.payload && Object.keys(err.output.payload).length) { //simple-oauth2 boom error error = err.output.payload; - } else { - // Something happened in setting up the request that triggered an Error error = err; - } Logger.error(error, config.homeName); - + return; - - } + } return { getStates: getStates, setStates: setStates, - changedStates: changedStates + changedStates: changedStates, }; - }; diff --git a/src/helper/logger.js b/src/helper/logger.js index d8a7d15..7006d63 100644 --- a/src/helper/logger.js +++ b/src/helper/logger.js @@ -4,27 +4,24 @@ var log = console; var debugMode = false; module.exports = { - - init: function(logger, debug){ - + init: function (logger, debug) { log = logger; //debugMode = process.argv.includes('-D') || process.argv.includes('--debug'); debugMode = debug; - + return; - }, - - formatMessage: function(message, device){ + + formatMessage: function (message, device) { device = typeof device === 'object' ? JSON.stringify(device) : device; let formatted = ''; if (device) { formatted += device + ': '; } - - if(message instanceof Error){ + + if (message instanceof Error) { formatted = message; - } else if(typeof message === 'object'){ + } else if (typeof message === 'object') { //formatted += JSON.stringify(message, null, 2); formatted += JSON.stringify(message); } else { @@ -33,23 +30,22 @@ module.exports = { return formatted; }, - info: function(message, device){ + info: function (message, device) { log.info(this.formatMessage(message, device)); }, - warn: function(message, device){ + warn: function (message, device) { log.warn(this.formatMessage(message, device)); }, - error: function(message, device){ + error: function (message, device) { log.error(this.formatMessage(message, device)); }, - debug: function(message, device){ + debug: function (message, device) { if (debugMode) { //log.debug(this.formatMessage(message, device)); log.info(this.formatMessage(message, device)); } - } - -}; \ No newline at end of file + }, +}; diff --git a/src/helper/telegram.js b/src/helper/telegram.js index 98840e8..0df09c0 100644 --- a/src/helper/telegram.js +++ b/src/helper/telegram.js @@ -5,69 +5,56 @@ const Logger = require('./logger.js'); const FormData = require('form-data'); class Telegram { - - constructor (options, messages) { - + constructor(options, messages) { this.token = options.token; this.chatID = options.chatID; this.messages = messages; - + this.request = { - protocol: 'https:', - host:'api.telegram.org', + protocol: 'https:', + host: 'api.telegram.org', port: 443, - method:'POST', - path: '/bot' + this.token + '/sendMessage' + method: 'POST', + path: '/bot' + this.token + '/sendMessage', }; - } - - send(target, dest, replacer, additional){ - - if(this.messages[target] && this.messages[target][dest]){ - - let message = this.messages[target][dest].includes('@') && replacer - ? this.messages[target][dest].replace('@', replacer) - : this.messages[target][dest]; - - message = message.includes('%') && additional - ? message.replace('%', additional) - : message; - + + send(target, dest, replacer, additional) { + if (this.messages[target] && this.messages[target][dest]) { + let message = + this.messages[target][dest].includes('@') && replacer + ? this.messages[target][dest].replace('@', replacer) + : this.messages[target][dest]; + + message = message.includes('%') && additional ? message.replace('%', additional) : message; + const form = new FormData(); - + this.request.headers = form.getHeaders(); form.append('chat_id', this.chatID); form.append('parse_mode', 'Markdown'); form.append('text', message); - + Logger.debug('Telegram: Sending Message: ' + message); - + form.submit(this.request, (err, res) => { - - if(err){ + if (err) { Logger.error('An error occured during sending telegram message!'); Logger.error(err); } - - if(res.statusCode < 200 || res.statusCode > 200){ + + if (res.statusCode < 200 || res.statusCode > 200) { Logger.error('A response error occured during sending telegram message!'); Logger.error({ code: res.statusCode, - message: res.statusMessage + message: res.statusMessage, }); } - }); - } else { - Logger.debug('Telegram: Skip sending, no message defined for ' + target); - } - } - } -module.exports = Telegram; \ No newline at end of file +module.exports = Telegram; diff --git a/src/platform.js b/src/platform.js index 7217d02..2603d58 100644 --- a/src/platform.js +++ b/src/platform.js @@ -30,22 +30,18 @@ const PLATFORM_NAME = 'TadoPlatform'; var Accessory, UUIDGen, FakeGatoHistoryService; module.exports = function (homebridge) { - Accessory = homebridge.platformAccessory; UUIDGen = homebridge.hap.uuid; - - return TadoPlatform; + return TadoPlatform; }; -function TadoPlatform (log, config, api) { - - if (!api||!config) - return; +function TadoPlatform(log, config, api) { + if (!api || !config) return; //init logger Logger.init(log, config.debug); - + //init types/fakegato CustomTypes.registerWith(api.hap); EveTypes.registerWith(api.hap); @@ -54,240 +50,189 @@ function TadoPlatform (log, config, api) { this.api = api; this.accessories = []; this.config = config; - + this.user = []; - + //setup config/plugin this.setupPlugin(); - - if(!this.user.length) - this.setupConfig(); + + if (!this.user.length) this.setupConfig(); this.api.on('didFinishLaunching', this.didFinishLaunching.bind(this)); - } TadoPlatform.prototype = { - - setupPlugin: async function(){ - + setupPlugin: async function () { try { - - if(this.config.user && this.config.user.length){ - - for(const credentials of this.config.user){ - + if (this.config.user && this.config.user.length) { + for (const credentials of this.config.user) { let error = false; - - if(!credentials.username){ + + if (!credentials.username) { Logger.warn('There is no username configured for the user. This user will be skipped.'); error = true; - } else if(!credentials.password){ + } else if (!credentials.password) { Logger.warn('There is no password configured for the user. This user will be skipped.'); error = true; - } else if(credentials.reconfigure === false){ + } else if (credentials.reconfigure === false) { error = true; } - - if(!error){ + + if (!error) { this.user.push({ username: credentials.username, - password: credentials.password + password: credentials.password, }); } - } - } - - if(this.user.length){ - - for(const user of this.user){ - - if(user.reconfigure || user.reconfigure === undefined){ - - if(this.config.homes && this.config.homes.length){ - - let foundHome = this.config.homes.filter(home => home && home.username === user.username); - - if(foundHome.length){ - + + if (this.user.length) { + for (const user of this.user) { + if (user.reconfigure || user.reconfigure === undefined) { + if (this.config.homes && this.config.homes.length) { + let foundHome = this.config.homes.filter((home) => home && home.username === user.username); + + if (foundHome.length) { //refresh - if(foundHome[0].name && foundHome[0].username && foundHome[0].password){ + if (foundHome[0].name && foundHome[0].username && foundHome[0].password) { Logger.info('Refreshing home...', foundHome[0].name); - this.config = await TadoConfig.refresh(foundHome[0].name, this.config, { username: foundHome[0].username, password: foundHome[0].password }); + this.config = await TadoConfig.refresh(foundHome[0].name, this.config, { + username: foundHome[0].username, + password: foundHome[0].password, + }); } - } else { - Logger.info('Generating new home...', user.username); this.config = await TadoConfig.add(this.config, [user]); - } - } else { - Logger.info('Generating new home...', user.username); this.config = await TadoConfig.add(this.config, [user]); - } - } - } - + //store config Logger.info('Storing config...'); - - this.config.user = this.user.map(user => { - return { - reconfigure: false, - username: user.username, - password: user.password - }; - }).filter(user => user); - + + this.config.user = this.user + .map((user) => { + return { + reconfigure: false, + username: user.username, + password: user.password, + }; + }) + .filter((user) => user); + await TadoConfig.store(this.config, this.api.user.storagePath()); - + Logger.info('Done!'); - + //setup config this.user = []; this.setupConfig(); - + //configure accessories - this.accessories.forEach(accessory => { + this.accessories.forEach((accessory) => { this.configureAccessory(accessory, true); }); - + //finish this.didFinishLaunching(); - } - - } catch(err){ - + } catch (err) { Logger.error('An error occured during setting up plugin!'); Logger.error(err); - } - + return; - }, - - setupConfig: function(){ - + + setupConfig: function () { try { - const { config, devices, deviceHandler, telegram } = TadoConfig.setup(this.config, UUIDGen); - + this.config = config; this.devices = devices; this.deviceHandler = deviceHandler; this.telegram = telegram; - - } catch(err) { - + } catch (err) { Logger.error('An error occured during setting up plugin!'); Logger.error(err); - } - + return; - }, - - didFinishLaunching: function(){ - - if(this.user.length) - return; - + + didFinishLaunching: function () { + if (this.user.length) return; + for (const entry of this.devices.entries()) { - let uuid = entry[0]; let device = entry[1]; - - const cachedAccessory = this.accessories.find(curAcc => curAcc.UUID === uuid); - + + const cachedAccessory = this.accessories.find((curAcc) => curAcc.UUID === uuid); + if (!cachedAccessory) { - const accessory = new Accessory(device.name, uuid); - Logger.info('Configuring new accessory...', accessory.displayName); - + Logger.info('Configuring new accessory...', accessory.displayName); + this.setupAccessory(accessory, device); - + this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - + this.accessories.push(accessory); - } - } - this.accessories.forEach(accessory => { - + this.accessories.forEach((accessory) => { const device = this.devices.get(accessory.UUID); - - try { - - if (!device) - this.removeAccessory(accessory); - - } catch(err) { + try { + if (!device) this.removeAccessory(accessory); + } catch (err) { Logger.info('It looks like the device has already been removed. Skip removing.', device.name); Logger.debug(err); - } - }); - - for(const entry of this.deviceHandler.entries()){ - + + for (const entry of this.deviceHandler.entries()) { const name = entry[0]; const config = entry[1]; - + const tado = config.tado; delete config.tado; - - let accessories = this.accessories - .filter(acc => acc && acc.context.config.homeName === name); - + + let accessories = this.accessories.filter((acc) => acc && acc.context.config.homeName === name); + const deviceHandler = DeviceHandler(this.api, accessories, config, tado, this.telegram); deviceHandler.getStates(); - } - }, - - setupAccessory: function(accessory, device){ - + + setupAccessory: function (accessory, device) { accessory.on('identify', () => { Logger.info('Identify requested.', accessory.displayName); }); - + const manufacturer = 'Tado'; - - const model = device.model - ? device.model - : device.subtype; - - const serialNumber = device.serialNumber - ? device.serialNumber - : '123456789'; - + + const model = device.model ? device.model : device.subtype; + + const serialNumber = device.serialNumber ? device.serialNumber : '123456789'; + const AccessoryInformation = accessory.getService(this.api.hap.Service.AccessoryInformation); - - AccessoryInformation - .setCharacteristic(this.api.hap.Characteristic.Manufacturer, manufacturer) + + AccessoryInformation.setCharacteristic(this.api.hap.Characteristic.Manufacturer, manufacturer) .setCharacteristic(this.api.hap.Characteristic.Model, model) .setCharacteristic(this.api.hap.Characteristic.SerialNumber, serialNumber) .setCharacteristic(this.api.hap.Characteristic.FirmwareRevision, packageFile.version); - + const tado = device.tado; - + delete device.tado; delete device.geolocation; delete device.zones; @@ -296,21 +241,21 @@ TadoPlatform.prototype = { delete device.weather; delete device.extras; delete device.childLock; - + accessory.context.config = device; - + const configHandler = this.deviceHandler.get(accessory.context.config.homeName); const deviceHandler = DeviceHandler(this.api, false, configHandler, tado, this.telegram); - + switch (device.subtype) { case 'zone-thermostat': - new ThermostatAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); - break; + new ThermostatAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); + break; case 'zone-heatercooler': case 'zone-heatercooler-boiler': new HeaterCoolerAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); break; - case 'zone-switch': + case 'zone-switch': case 'zone-window-switch': case 'extra-childswitch': case 'extra-cntrlswitch': @@ -318,11 +263,11 @@ TadoPlatform.prototype = { case 'extra-shedule': case 'extra-turnoff': case 'extra-plockswitch': - new SwitchAccessory(this.api, accessory, this.accessories, tado, deviceHandler); - break; + new SwitchAccessory(this.api, accessory, this.accessories, tado, deviceHandler); + break; case 'zone-faucet': new FaucetAccessory(this.api, accessory, this.accessories, tado, deviceHandler); - break; + break; case 'zone-window-contact': new ContactAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); break; @@ -335,8 +280,8 @@ TadoPlatform.prototype = { case 'presence-motion': new MotionAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); break; - case 'presence-occupancy': - new OccupancyAccessory(this.api, accessory, this.accessories, tado, deviceHandler); + case 'presence-occupancy': + new OccupancyAccessory(this.api, accessory, this.accessories, tado, deviceHandler); break; case 'weather-temperature': new TemperatureAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); @@ -354,48 +299,39 @@ TadoPlatform.prototype = { new SecurityAccessory(this.api, accessory, this.accessories, tado, deviceHandler); break; default: - Logger.warn('Unknown accessory type: ' + device.subtype, accessory.displayName); + Logger.warn('Unknown accessory type: ' + device.subtype, accessory.displayName); break; } - - return; + return; }, - configureAccessory: function(accessory, refresh){ - - if(!this.user.length){ - + configureAccessory: function (accessory, refresh) { + if (!this.user.length) { const device = this.devices.get(accessory.UUID); - - if (device){ + + if (device) { Logger.info('Configuring accessory...', accessory.displayName); this.setupAccessory(accessory, device); } - } - - if(!refresh) - this.accessories.push(accessory); - + + if (!refresh) this.accessories.push(accessory); }, - - removeAccessory: function(accessory) { - + + removeAccessory: function (accessory) { Logger.info('Removing accessory...', accessory.displayName); - - let accessories = this.accessories.map( cachedAccessory => { - if(cachedAccessory.displayName !== accessory.displayName){ + + let accessories = this.accessories.map((cachedAccessory) => { + if (cachedAccessory.displayName !== accessory.displayName) { return cachedAccessory; } }); - + this.accessories = accessories.filter(function (el) { return el != null; }); this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - - } - -}; \ No newline at end of file + }, +}; diff --git a/src/tado/tado-api.js b/src/tado/tado-api.js index 9868854..e2a8380 100644 --- a/src/tado/tado-api.js +++ b/src/tado/tado-api.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict'; const Logger = require('../helper/logger.js'); @@ -9,31 +9,27 @@ const EXPIRATION_WINDOW_IN_SECONDS = 300; const tado_url = 'https://my.tado.com'; class Tado { - - constructor(name, credentials) { - + constructor(name, credentials) { this.credentials = credentials; this.name = name; - + //https://my.tado.com/webapp/env.js const params = { client: { id: 'tado-web-app', - secret: 'wZaRN7rpjn3FoNyF5IFuxg9uMzYJcvOoQ8QWiIqS3hfk6gLhVlG57j5YNoZL2Rtc' + secret: 'wZaRN7rpjn3FoNyF5IFuxg9uMzYJcvOoQ8QWiIqS3hfk6gLhVlG57j5YNoZL2Rtc', }, auth: { - tokenHost: 'https://auth.tado.com' - } + tokenHost: 'https://auth.tado.com', + }, }; - + this.client = new ResourceOwnerPassword(params); Logger.debug('API successfull initialized', this.name); - } - + async _login() { - const tokenParams = { username: this.credentials.username, password: this.credentials.password, @@ -41,74 +37,79 @@ class Tado { }; this._accessToken = await this.client.getToken(tokenParams); - } async _refreshToken() { - if (!this._accessToken) { await this._login(); } - + if (this._accessToken.expired(EXPIRATION_WINDOW_IN_SECONDS)) { - Logger.debug('Access Token expired! Refreshing token...', this.name); - + this._accessToken = await this._accessToken.refresh(); - + Logger.debug('Access token refreshed!', this.name); - } else { - Logger.debug('Access token NOT expired', this.name); - } - + return; - } async apiCall(path, method = 'GET', data = {}, params = {}, tado_url_dif, blockLog) { - Logger.debug('Checking access token..', this.name); - + await this._refreshToken(); - + let tadoLink = tado_url_dif || tado_url; - + Logger.debug('Using ' + tadoLink, this.name); - - Logger.debug('API request ' + method + ' ' + path + ' ' + (data && Object.keys(data).length ? JSON.stringify(data) + ' ': ''), this.name); - + + Logger.debug( + 'API request ' + + method + + ' ' + + path + + ' ' + + (data && Object.keys(data).length ? JSON.stringify(data) + ' ' : ''), + this.name + ); + let config = { method: method, responseType: 'json', headers: { - Authorization: 'Bearer ' + this._accessToken.token.access_token + Authorization: 'Bearer ' + this._accessToken.token.access_token, }, timeout: 30000, retry: { limit: 2, statusCodes: [408, 429, 503, 504], - methods: ['GET', 'POST', 'DELETE', 'PUT'] - } + methods: ['GET', 'POST', 'DELETE', 'PUT'], + }, }; - - if(Object.keys(data).length) - config.json = data; - - if(Object.keys(params).length) - config.searchParams = params; - + + if (Object.keys(data).length) config.json = data; + + if (Object.keys(params).length) config.searchParams = params; + const response = await got(tadoLink + path, config); - - Logger.debug('API request ' + method + ' ' + path + ' ' + (data && Object.keys(data).length ? JSON.stringify(data) + ' ': ''), this.name); - - if(!blockLog) - Logger.debug('API request ' + method + ' ' + path + ' ' + JSON.stringify(response.body), this.name); - + + Logger.debug( + 'API request ' + + method + + ' ' + + path + + ' ' + + (data && Object.keys(data).length ? JSON.stringify(data) + ' ' : ''), + this.name + ); + + if (!blockLog) + Logger.debug('API request ' + method + ' ' + path + ' ' + JSON.stringify(response.body), this.name); + return response.body; - } async getMe() { @@ -174,7 +175,7 @@ class Tado { } async getZoneOverlay(home_id, zone_id) { - return this.apiCall(`/api/v2/homes/${home_id}/zones/${zone_id}/overlay`).catch(error => { + return this.apiCall(`/api/v2/homes/${home_id}/zones/${zone_id}/overlay`).catch((error) => { if (error.response.status === 404) { return {}; } @@ -215,24 +216,15 @@ class Tado { config.setting.power = 'ON'; if (temperature && !isNaN(temperature)) { - - if(tempUnit.toLowerCase() === 'fahrenheit') - temperature = (temperature - 32) * 5/9; - + if (tempUnit.toLowerCase() === 'fahrenheit') temperature = ((temperature - 32) * 5) / 9; + config.setting.temperature = { celsius: temperature }; - } else { - config.setting.temperature = null; - } - - } else { - config.setting.power = 'OFF'; config.setting.temperature = null; - } if (!isNaN(parseInt(termination))) { @@ -261,7 +253,7 @@ class Tado { async identifyDevice(device_id) { return this.apiCall(`/api/v2/devices/${device_id}/identify`, 'POST'); } - + async getPresenceLock(home_id) { return this.apiCall(`/api/v2/homes/${home_id}/state`); } @@ -275,7 +267,7 @@ class Tado { const method = presence == 'AUTO' ? 'DELETE' : 'PUT'; const config = { - homePresence: presence + homePresence: presence, }; return this.apiCall(`/api/v2/homes/${home_id}/presenceLock`, method, config); @@ -300,16 +292,15 @@ class Tado { if (isAnyoneAtHome !== isPresenceAtHome) { return this.setPresenceLock(home_id, isAnyoneAtHome ? 'HOME' : 'AWAY'); - } - else { + } else { return 'already up to date'; } } async setWindowDetection(home_id, zone_id, enabled, timeout) { const config = { - 'enabled': enabled, - 'timeoutInSeconds': timeout, + enabled: enabled, + timeoutInSeconds: timeout, }; return this.apiCall(`/api/v2/homes/${home_id}/zones/${zone_id}/openWindowDetection`, 'PUT', config); } @@ -325,104 +316,89 @@ class Tado { async getAirComfort(home_id) { return this.apiCall(`/api/v2/homes/${home_id}/airComfort`); } - + async getWeatherAirComfort(home_id, longitude, latitude) { let geoLocation = { longitude: longitude, - latitude: latitude + latitude: latitude, }; - - if(!geoLocation.longitude || !geoLocation.latitude){ + + if (!geoLocation.longitude || !geoLocation.latitude) { const data = await this.getHome(home_id); geoLocation = data.geolocation; } return this.apiCall(`/v1/homes/${home_id}/airComfort`, 'GET', {}, geoLocation, 'https://acme.tado.com'); } - + async setChildLock(serialNumber, state) { - if (!serialNumber) { throw new Error('Cannot change child lock state. No serialNumber is given.'); } - - return this.apiCall(`/api/v2/devices/${serialNumber}/childLock`, 'PUT', { 'childLockEnabled': state }); - + + return this.apiCall(`/api/v2/devices/${serialNumber}/childLock`, 'PUT', { childLockEnabled: state }); } - + async switchAll(home_id, zones = []) { - const postData = { - overlays: [] + overlays: [], }; - - zones.forEach(zone => { - + + zones.forEach((zone) => { const zoneData = { room: zone.id, overlay: { setting: { power: zone.power || 'OFF', - type: zone.type || 'HEATING' - } + type: zone.type || 'HEATING', + }, }, termination: { - typeSkillBasedApp: zone.termination || 'MANUAL' - } + typeSkillBasedApp: zone.termination || 'MANUAL', + }, }; - - if(zone.maxTempInCelsius){ + + if (zone.maxTempInCelsius) { zoneData.overlay.setting.temperature = { celsius: zone.maxTempInCelsius, - fahrenheit: Math.round(((zone.maxTempInCelsius * 9 / 5 + 32) + Number.EPSILON) * 100) / 100 + fahrenheit: Math.round(((zone.maxTempInCelsius * 9) / 5 + 32 + Number.EPSILON) * 100) / 100, }; } - - if(zone.termination === 'TIMER'){ - zoneData.termination.durationInSeconds = zone.timer > 0 - ? zone.timer * 60 - : 1800; + + if (zone.termination === 'TIMER') { + zoneData.termination.durationInSeconds = zone.timer > 0 ? zone.timer * 60 : 1800; } - + postData.overlays.push(zoneData); - }); - + return this.apiCall(`/api/v2/homes/${home_id}/overlay`, 'POST', postData); - } - - async resumeShedule(home_id, roomIds = []){ - + + async resumeShedule(home_id, roomIds = []) { if (!roomIds.length) { throw new Error('Can not resume shedule for zones, no room ids given!'); } - + const params = { - rooms: roomIds.toString() + rooms: roomIds.toString(), }; - + return this.apiCall(`/api/v2/homes/${home_id}/overlay`, 'DELETE', {}, params); - } - - async getRunningTime(home_id, time, from, to){ - const period = { + async getRunningTime(home_id, time, from, to) { + const period = { aggregate: time || 'day', - summary_only: true + summary_only: true, }; - - if(from) - period.from = from; - - if(to) - period.to = to; - + + if (from) period.from = from; + + if (to) period.to = to; + return this.apiCall(`/v1/homes/${home_id}/runningTimes`, 'GET', {}, period, 'https://minder.tado.com', false); - } - } module.exports = Tado; diff --git a/src/tado/tado-config.js b/src/tado/tado-config.js index 5528e79..bb2b07f 100644 --- a/src/tado/tado-config.js +++ b/src/tado/tado-config.js @@ -7,7 +7,13 @@ const TadoApi = require('./tado-api.js'); const Telegram = require('../helper/telegram'); //https://stackoverflow.com/a/15710692 -const hashCode = s => Math.abs(s.split('').reduce((a,b)=>{a=((a<<5)-a)+b.charCodeAt(0);return a&a;},0)).toString(); +const hashCode = (s) => + Math.abs( + s.split('').reduce((a, b) => { + a = (a << 5) - a + b.charCodeAt(0); + return a & a; + }, 0) + ).toString(); const devices = new Map(); const deviceHandler = new Map(); @@ -15,48 +21,46 @@ const deviceHandler = new Map(); let telegram; module.exports = { - - add: async function(config, credentials){ - + add: async function (config, credentials) { config.homes = config.homes || []; - - for(const user of credentials){ - + + for (const user of credentials) { let username = user.username; let password = user.password; - - const tado = new TadoApi('Configuration', { username: username, password: password }); - + + const tado = new TadoApi('Configuration', { + username: username, + password: password, + }); + const me = await tado.getMe(); - - for(const foundHome of me.homes){ - + + for (const foundHome of me.homes) { let homeIndex; config.homes.forEach((home, index) => { - if(home.name === foundHome.name || home.id === foundHome.id){ + if (home.name === foundHome.name || home.id === foundHome.id) { homeIndex = index; } }); - - if(homeIndex === undefined){ - + + if (homeIndex === undefined) { const homeConfig = { id: foundHome.id, name: foundHome.name, username: username, - password: password, + password: password, polling: 30, zones: [], presence: { anyone: false, accTypeAnyone: 'OCCUPANCY', - user: [] + user: [], }, weather: { temperatureSensor: false, solarIntensity: false, accTypeSolarIntensity: 'LIGHTBULB', - airQuality: false + airQuality: false, }, extras: { centralSwitch: false, @@ -67,50 +71,50 @@ module.exports = { presenceLock: false, accTypePresenceLock: 'ALARM', accTypeChildLock: 'SWITCH', - childLockSwitches: [] + childLockSwitches: [], }, telegram: { - active: false - } + active: false, + }, }; - + //Home Informations const homeInfo = await tado.getHome(foundHome.id); - + homeConfig.temperatureUnit = homeInfo.temperatureUnit; homeConfig.geolocation = { longitude: homeInfo.geolocation.longitude.toString(), - latitude: homeInfo.geolocation.latitude.toString() + latitude: homeInfo.geolocation.latitude.toString(), }; - + //Mobile Devices Informations - const mobileDevices = await tado.getMobileDevices(foundHome.id); - - homeConfig.presence.user = mobileDevices.map(user => { + const mobileDevices = await tado.getMobileDevices(foundHome.id); + + homeConfig.presence.user = mobileDevices.map((user) => { return { active: false, name: user.name, - accType: 'OCCUPANCY' + accType: 'OCCUPANCY', }; - }); - + }); + //Zone Informations - const zones = await tado.getZones(foundHome.id); - - for(const zone of zones){ - - if(zone.devices) - zone.devices.forEach(device => { - if(device.deviceType && (device.deviceType.includes('VA01') || device.deviceType.includes('VA02'))) //https://community.tado.com/en-gb/discussion/705/released-child-lock + const zones = await tado.getZones(foundHome.id); + + for (const zone of zones) { + if (zone.devices) + zone.devices.forEach((device) => { + if (device.deviceType && (device.deviceType.includes('VA01') || device.deviceType.includes('VA02'))) + //https://community.tado.com/en-gb/discussion/705/released-child-lock homeConfig.extras.childLockSwitches.push({ active: false, name: zone.name + ' ' + device.shortSerialNo, - serialNumber: device.shortSerialNo + serialNumber: device.shortSerialNo, }); }); - - const capabilities = await tado.getZoneCapabilities(foundHome.id, zone.id); - + + const capabilities = await tado.getZoneCapabilities(foundHome.id, zone.id); + homeConfig.zones.push({ active: true, id: zone.id, @@ -122,15 +126,21 @@ module.exports = { mode: 'MANUAL', modeTimer: 30, easyMode: false, - minValue: homeConfig.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.min - : capabilities.temperatures.fahrenheit.min, - maxValue: homeConfig.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.max - : capabilities.temperatures.fahrenheit.max, - minStep: homeConfig.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.step - : capabilities.temperatures.fahrenheit.step, + minValue: capabilities.temperatures + ? homeConfig.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.min + : capabilities.temperatures.fahrenheit.min + : 5, + maxValue: capabilities.temperatures + ? homeConfig.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.max + : capabilities.temperatures.fahrenheit.max + : 25, + minStep: capabilities.temperatures + ? homeConfig.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.step + : capabilities.temperatures.fahrenheit.step + : 1, openWindowSensor: false, openWindowSwitch: false, accTypeOpenWindowSwitch: 'SWITCH', @@ -138,225 +148,221 @@ module.exports = { separateTemperature: false, separateHumidity: false, accTypeBoiler: 'SWITCH', - boilerTempSupport: false + boilerTempSupport: false, }); - } - + config.homes.push(homeConfig); - } - } - - } - + } + return config; - }, - - resync: async function(config, credentials){ - + + resync: async function (config, credentials) { const availableHomesInApis = []; - - for(const user of credentials){ - + + for (const user of credentials) { //Init API with credentials - const tado = new TadoApi('Configuration', { username: user.username, password: user.password }); + const tado = new TadoApi('Configuration', { + username: user.username, + password: user.password, + }); const me = await tado.getMe(); - - me.homes.forEach(foundHome => { + + me.homes.forEach((foundHome) => { availableHomesInApis.push({ id: foundHome.id, name: foundHome.name, username: user.username, - password: user.password + password: user.password, }); }); - } - + //remove non exist homes from config that doesnt exist in api - for(let [i, home] of config.homes.entries()){ - + for (let [i, home] of config.homes.entries()) { let foundHome; - - for(const apiHome of availableHomesInApis){ - if(home.name === apiHome.name || home.id === apiHome.id){ + + for (const apiHome of availableHomesInApis) { + if (home.name === apiHome.name || home.id === apiHome.id) { foundHome = apiHome; } } - - if(!foundHome){ + + if (!foundHome) { config.homes.splice(i, 1); } - - } - + } + //refresh existing homes - for(let home of config.homes.entries()){ - if(home.name && home.username && home.password){ - config = await this.refresh(home.name, config, { username: home.username, password: home.password }); - } + for (let home of config.homes.entries()) { + if (home.name && home.username && home.password) { + config = await this.refresh(home.name, config, { + username: home.username, + password: home.password, + }); + } } - + config = await this.add(config, availableHomesInApis); - + return config; - }, - refresh: async function(currentHome, config, credentials){ - + refresh: async function (currentHome, config, credentials) { let username = credentials.username; let password = credentials.password; - - const tado = new TadoApi('Configuration', { username: username, password: password }); - + + const tado = new TadoApi('Configuration', { + username: username, + password: password, + }); + //Home Informations - let home = config.homes.find(home => home && home.name === currentHome); - - if(!home) - throw new Error('Cannot refresh ' + currentHome + '. Not found in config!'); - - if(!home.id){ + let home = config.homes.find((home) => home && home.name === currentHome); + if (!home) throw new Error('Cannot refresh ' + currentHome + '. Not found in config!'); + + if (!home.id) { const me = await tado.getMe(); - - me.homes.map(foundHome => { - if(foundHome.name === home.name) - home.id = foundHome.id; + + me.homes.map((foundHome) => { + if (foundHome.name === home.name) home.id = foundHome.id; }); - - if(!home.id) + + if (!home.id) throw new Error('Cannot get a Home ID for ' + home.name + '. ' + home.name + ' not found for this user!'); - } - + const homeInfo = await tado.getHome(home.id); - - for(let [i, home] of config.homes.entries()){ - - if(config.homes[i].name === homeInfo.name){ - + + for (let [i, home] of config.homes.entries()) { + if (config.homes[i].name === homeInfo.name) { config.homes[i].id = homeInfo.id; config.homes[i].username = credentials.username; config.homes[i].password = credentials.password; config.homes[i].temperatureUnit = homeInfo.temperatureUnit || 'CELSIUS'; - config.homes[i].zones = config.homes[i].zones || []; - - if(homeInfo.geolocation) + config.homes[i].zones = config.homes[i].zones || []; + + if (homeInfo.geolocation) config.homes[i].geolocation = { longitude: homeInfo.geolocation.longitude.toString(), - latitude: homeInfo.geolocation.latitude.toString() + latitude: homeInfo.geolocation.latitude.toString(), }; - + //init devices for childLock config.homes[i].extras = config.homes[i].extras || {}; config.homes[i].extras.childLockSwitches = config.homes[i].extras.childLockSwitches || []; - - let allFoundDevices = []; - + + let allFoundDevices = []; + //Mobile Devices Informations - const mobileDevices = await tado.getMobileDevices(home.id); - - if(!config.homes[i].presence) + const mobileDevices = await tado.getMobileDevices(home.id); + + if (!config.homes[i].presence) config.homes[i].presence = { anyone: false, accTypeAnyone: 'OCCUPANCY', - user: [] + user: [], }; - + //Remove not registred devices config.homes[i].presence.user.forEach((user, index) => { let found = false; - mobileDevices.forEach(foundUser => { - if(foundUser.name === user.name){ + mobileDevices.forEach((foundUser) => { + if (foundUser.name === user.name) { found = true; } }); - if(!found){ + if (!found) { config.homes[i].presence.user.splice(index, 1); } }); - + //Check for new registred devices - if(config.homes[i].presence.user.length){ - for(const foundUser of mobileDevices){ + if (config.homes[i].presence.user.length) { + for (const foundUser of mobileDevices) { let userIndex; config.homes[i].presence.user.forEach((user, index) => { - if(user.name === foundUser.name){ + if (user.name === foundUser.name) { userIndex = index; } }); - if(userIndex === undefined){ + if (userIndex === undefined) { config.homes[i].presence.user.push({ active: false, name: foundUser.name, - accType: 'OCCUPANCY' + accType: 'OCCUPANCY', }); } } } else { - config.homes[i].presence.user = mobileDevices.map(user => { + config.homes[i].presence.user = mobileDevices.map((user) => { return { active: false, name: user.name, - accType: 'OCCUPANCY' + accType: 'OCCUPANCY', }; - }); - } - + }); + } + //Zone Informations - const zones = await tado.getZones(home.id); - + const zones = await tado.getZones(home.id); + //Remove not available zones config.homes[i].zones.forEach((zone, index) => { let found = false; - zones.forEach(foundZone => { - if(foundZone.name === zone.name){ + zones.forEach((foundZone) => { + if (foundZone.name === zone.name) { found = true; } }); - if(!found){ + if (!found) { config.homes[i].zones.splice(index, 1); } }); - + //Check for new zones or refresh exist one - if(config.homes[i].zones.length){ - for(const foundZone of zones){ - - const capabilities = await tado.getZoneCapabilities(home.id, foundZone.id); - - if(foundZone.devices) - foundZone.devices.forEach(dev => { - if(dev.deviceType && (dev.deviceType.includes('VA01') || dev.deviceType.includes('VA02'))) + if (config.homes[i].zones.length) { + for (const foundZone of zones) { + const capabilities = await tado.getZoneCapabilities(home.id, foundZone.id); + + if (foundZone.devices) + foundZone.devices.forEach((dev) => { + if (dev.deviceType && (dev.deviceType.includes('VA01') || dev.deviceType.includes('VA02'))) allFoundDevices.push({ name: foundZone.name + ' ' + dev.shortSerialNo, - serialNumber: dev.shortSerialNo + serialNumber: dev.shortSerialNo, }); }); - + let zoneIndex; config.homes[i].zones.forEach((zone, index) => { - if(zone.name === foundZone.name){ + if (zone.name === foundZone.name) { zoneIndex = index; } }); - if(zoneIndex !== undefined){ + if (zoneIndex !== undefined) { config.homes[i].zones[zoneIndex].id = foundZone.id; config.homes[i].zones[zoneIndex].type = foundZone.type; - config.homes[i].zones[zoneIndex].minValue = homeInfo.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.min - : capabilities.temperatures.fahrenheit.min; - config.homes[i].zones[zoneIndex].maxValue = homeInfo.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.max - : capabilities.temperatures.fahrenheit.max; - config.homes[i].zones[zoneIndex].minStep = homeInfo.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.step - : capabilities.temperatures.fahrenheit.step; + config.homes[i].zones[zoneIndex].minValue = capabilities.temperatures + ? homeInfo.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.min + : capabilities.temperatures.fahrenheit.min + : 5; + config.homes[i].zones[zoneIndex].maxValue = capabilities.temperatures + ? homeInfo.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.max + : capabilities.temperatures.fahrenheit.max + : 25; + config.homes[i].zones[zoneIndex].minStep = capabilities.temperatures + ? homeInfo.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.step + : capabilities.temperatures.fahrenheit.step + : 1; } else { config.homes[i].zones.push({ active: true, @@ -368,15 +374,21 @@ module.exports = { noBattery: false, mode: 'MANUAL', modeTimer: 30, - minValue: homeInfo.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.min - : capabilities.temperatures.fahrenheit.min, - maxValue: homeInfo.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.max - : capabilities.temperatures.fahrenheit.max, - minStep: homeInfo.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.step - : capabilities.temperatures.fahrenheit.step, + minValue: capabilities.temperatures + ? homeInfo.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.min + : capabilities.temperatures.fahrenheit.min + : 5, + maxValue: capabilities.temperatures + ? homeInfo.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.max + : capabilities.temperatures.fahrenheit.max + : 25, + minStep: capabilities.temperatures + ? homeInfo.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.step + : capabilities.temperatures.fahrenheit.step + : 1, easyMode: false, openWindowSensor: false, openWindowSwitch: false, @@ -385,25 +397,23 @@ module.exports = { separateTemperature: false, separateHumidity: false, accTypeBoiler: 'SWITCH', - boilerTempSupport: false + boilerTempSupport: false, }); - } + } } } else { - - for(const zone of zones){ - - const capabilities = await tado.getZoneCapabilities(home.id, zone.id); - - if(zone.devices) - zone.devices.forEach(dev => { - if(dev.deviceType && (dev.deviceType.includes('VA01') || dev.deviceType.includes('VA02'))) + for (const zone of zones) { + const capabilities = await tado.getZoneCapabilities(home.id, zone.id); + + if (zone.devices) + zone.devices.forEach((dev) => { + if (dev.deviceType && (dev.deviceType.includes('VA01') || dev.deviceType.includes('VA02'))) allFoundDevices.push({ name: zone.name + ' ' + dev.shortSerialNo, - serialNumber: dev.shortSerialNo + serialNumber: dev.shortSerialNo, }); }); - + config.homes[i].zones.push({ active: true, id: zone.id, @@ -414,15 +424,21 @@ module.exports = { noBattery: false, mode: 'MANUAL', modeTimer: 30, - minValue: homeInfo.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.min - : capabilities.temperatures.fahrenheit.min, - maxValue: homeInfo.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.max - : capabilities.temperatures.fahrenheit.max, - minStep: homeInfo.temperatureUnit === 'CELSIUS' - ? capabilities.temperatures.celsius.step - : capabilities.temperatures.fahrenheit.step, + minValue: capabilities.temperatures + ? homeInfo.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.min + : capabilities.temperatures.fahrenheit.min + : 5, + maxValue: capabilities.temperatures + ? homeInfo.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.max + : capabilities.temperatures.fahrenheit.max + : 25, + minStep: capabilities.temperatures + ? homeInfo.temperatureUnit === 'CELSIUS' + ? capabilities.temperatures.celsius.step + : capabilities.temperatures.fahrenheit.step + : 1, easyMode: false, openWindowSensor: false, openWindowSwitch: false, @@ -431,70 +447,62 @@ module.exports = { separateTemperature: false, separateHumidity: false, accTypeBoiler: 'SWITCH', - boilerTempSupport: false + boilerTempSupport: false, }); - } - } - + //remove non existing childLockSwitches config.homes[i].extras.childLockSwitches.forEach((childLockSwitch, index) => { let found = false; - allFoundDevices.forEach(foundDevice => { - if(foundDevice.serialNumber === childLockSwitch.serialNumber){ + allFoundDevices.forEach((foundDevice) => { + if (foundDevice.serialNumber === childLockSwitch.serialNumber) { found = true; } }); - if(!found){ + if (!found) { config.homes[i].extras.childLockSwitches.splice(index, 1); } }); - + //check for new childLockSwitches - if(config.homes[i].extras.childLockSwitches.length){ - for(const foundDevice of allFoundDevices){ + if (config.homes[i].extras.childLockSwitches.length) { + for (const foundDevice of allFoundDevices) { let found = false; - config.homes[i].extras.childLockSwitches.forEach(childLockSwitch => { - if(childLockSwitch.serialNumber === foundDevice.serialNumber){ + config.homes[i].extras.childLockSwitches.forEach((childLockSwitch) => { + if (childLockSwitch.serialNumber === foundDevice.serialNumber) { found = true; } }); - if(!found){ + if (!found) { config.homes[i].extras.childLockSwitches.push({ active: false, name: foundDevice.name, - serialNumber: foundDevice.serialNumber + serialNumber: foundDevice.serialNumber, }); - } + } } } else { - config.homes[i].extras.childLockSwitches = allFoundDevices.map(device => { + config.homes[i].extras.childLockSwitches = allFoundDevices.map((device) => { return { active: false, name: device.name, - serialNumber: device.serialNumber + serialNumber: device.serialNumber, }; - }); + }); } - } - } - + return config; - }, - - setup: function(config, UUIDGen){ - - if(config.homes && config.homes.length) { - - config.homes.forEach(home => { - + + setup: function (config, UUIDGen) { + if (config.homes && config.homes.length) { + config.homes.forEach((home) => { let error = false; let activeZones = 0; - + if (!home.name) { Logger.warn('There is no name configured for this home. This home will be skipped.'); error = true; @@ -505,12 +513,14 @@ module.exports = { Logger.warn('There is no password configured for this home. This home will be skipped.', home.name); error = true; } - - if (!error) { - + + if (!error) { //Base Config - const tado = new TadoApi(home.name, { username: home.username, password: home.password }); - + const tado = new TadoApi(home.name, { + username: home.username, + password: home.password, + }); + const accessoryConfig = { homeId: home.id, homeName: home.name, @@ -523,72 +533,64 @@ module.exports = { accTypeAnyone: home.presence && home.presence.accTypeAnyone, weather: home.weather || {}, extras: home.extras || {}, - zones: home.zones - ? home.zones.filter(zone => zone && zone.active) - : [], - presence: home.presence && home.presence.user - ? home.presence.user.filter(user => user && user.active) - : [], - childLock: home.extras && home.extras.childLockSwitches - ? home.extras.childLockSwitches.filter(childLockSwitch => childLockSwitch && childLockSwitch.active) - : [], - polling: Number.isInteger(home.polling) - ? home.polling < 30 - ? 30 - : home.polling - : 30 + zones: home.zones ? home.zones.filter((zone) => zone && zone.active) : [], + presence: + home.presence && home.presence.user ? home.presence.user.filter((user) => user && user.active) : [], + childLock: + home.extras && home.extras.childLockSwitches + ? home.extras.childLockSwitches.filter((childLockSwitch) => childLockSwitch && childLockSwitch.active) + : [], + polling: Number.isInteger(home.polling) ? (home.polling < 30 ? 30 : home.polling) : 30, }; - - if(home.zones && home.zones.length){ - + + if (home.zones && home.zones.length) { let validOpenWindowSwitches = []; - - home.zones.forEach(zone => { - - if(zone.active){ - + + home.zones.forEach((zone) => { + if (zone.active) { let valid_boilerTypes = ['SWITCH', 'FAUCET']; let valid_zoneTypes = ['HEATING', 'HOT_WATER']; let valid_modes = ['MANUAL', 'AUTO', 'TIMER', 'CUSTOM']; - - if(!zone.name) { + + if (!zone.name) { Logger.warn('There is no name configured for this zone. This zone will be skipped.', home.name); error = true; - } else if(!valid_zoneTypes.includes(zone.type)){ - Logger.warn('There is no or no correct zone type configured for this zone. Setting it to "HEATING".', zone.name); + } else if (!valid_zoneTypes.includes(zone.type)) { + Logger.warn( + 'There is no or no correct zone type configured for this zone. Setting it to "HEATING".', + zone.name + ); zone.type = 'HEATING'; - } - - if(!error){ - + } + + if (!error) { activeZones += 1; - + const name = home.name + ' ' + zone.name + (zone.type === 'HEATING' ? ' Heater' : ' Boiler'); - + const uuid = UUIDGen.generate(name); - + if (devices.has(uuid)) { - - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name); - + Logger.warn( + 'Multiple devices are configured with this name. Duplicate devices will be skipped.', + name + ); } else { - let config = { ...accessoryConfig }; - - config.name = name; - - config.subtype = zone.type === 'HEATING' - ? zone.easyMode - ? 'zone-heatercooler' - : 'zone-thermostat' - : valid_boilerTypes.includes(zone.accTypeBoiler) && zone.accTypeBoiler === 'FAUCET' + + config.name = name; + + config.subtype = + zone.type === 'HEATING' + ? zone.easyMode + ? 'zone-heatercooler' + : 'zone-thermostat' + : valid_boilerTypes.includes(zone.accTypeBoiler) && zone.accTypeBoiler === 'FAUCET' ? 'zone-faucet' - : 'zone-switch'; - - config.subtype = zone.boilerTempSupport - ? 'zone-heatercooler-boiler' - : config.subtype; - + : 'zone-switch'; + + config.subtype = zone.boilerTempSupport ? 'zone-heatercooler-boiler' : config.subtype; + config.zoneId = zone.id; config.type = zone.type; config.airQuality = zone.airQuality; @@ -600,532 +602,431 @@ module.exports = { config.openWindowSensor = zone.openWindowSensor; config.openWindowSwitch = zone.openWindowSwitch; config.noBattery = zone.noBattery; - config.mode = valid_modes.includes(zone.mode) - ? zone.mode - : 'MANUAL'; - config.modeTimer = zone.modeTimer && zone.modeTimer >= 1 - ? zone.modeTimer - : 1; + config.mode = valid_modes.includes(zone.mode) ? zone.mode : 'MANUAL'; + config.modeTimer = zone.modeTimer && zone.modeTimer >= 1 ? zone.modeTimer : 1; config.delaySwitch = zone.delaySwitch; config.autoOffDelay = zone.autoOffDelay; config.model = zone.type; config.serialNumber = hashCode(name); - + devices.set(uuid, config); - + //Configure openWindowSensor - if(zone.openWindowSensor){ - + if (zone.openWindowSensor) { const thisName = home.name + ' ' + zone.name + ' Window'; - + const uuid2 = UUIDGen.generate(thisName); - + if (devices.has(uuid2)) { - - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', thisName); - + Logger.warn( + 'Multiple devices are configured with this name. Duplicate devices will be skipped.', + thisName + ); } else { - let newConfig = { ...config }; newConfig.name = thisName; newConfig.subtype = 'zone-window-contact'; newConfig.model = newConfig.subtype; newConfig.serialNumber = hashCode(zone.name); - + devices.set(uuid2, newConfig); - } - } - + //Configure openWindowSwitch - if(zone.openWindowSwitch){ - + if (zone.openWindowSwitch) { validOpenWindowSwitches.push({ name: zone.name + ' Window', - zoneId: zone.id + zoneId: zone.id, }); - } - + //Configure Separate TemperatureSensor - if(zone.separateTemperature){ - + if (zone.separateTemperature) { const thisName = home.name + ' ' + zone.name + ' Temperature'; - + const uuid2 = UUIDGen.generate(thisName); - + if (devices.has(uuid2)) { - - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', thisName); - + Logger.warn( + 'Multiple devices are configured with this name. Duplicate devices will be skipped.', + thisName + ); } else { - let newConfig = { ...config }; newConfig.name = thisName; newConfig.subtype = 'zone-temperature'; newConfig.model = newConfig.subtype; newConfig.serialNumber = hashCode(zone.name); - + devices.set(uuid2, newConfig); - } - } - + //Configure Separate HumiditySensor - if(zone.separateHumidity){ - + if (zone.separateHumidity) { const thisName = home.name + ' ' + zone.name + ' Humidity'; - + const uuid2 = UUIDGen.generate(thisName); - + if (devices.has(uuid2)) { - - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', thisName); - + Logger.warn( + 'Multiple devices are configured with this name. Duplicate devices will be skipped.', + thisName + ); } else { - let newConfig = { ...config }; newConfig.name = thisName; newConfig.subtype = 'zone-humidity'; newConfig.model = newConfig.subtype; newConfig.serialNumber = hashCode(zone.name); - + devices.set(uuid2, newConfig); - } - } - } - } - } - }); - - if(validOpenWindowSwitches.length){ - + + if (validOpenWindowSwitches.length) { const name = home.name + ' Open Window'; const uuid = UUIDGen.generate(name); - + if (devices.has(uuid)) { - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name); - } else { - let config = { ...accessoryConfig }; - + config.name = name; config.subtype = 'zone-window-switch'; - config.openWindows = validOpenWindowSwitches; + config.openWindows = validOpenWindowSwitches; config.model = config.subtype; config.serialNumber = hashCode(name); - + devices.set(uuid, config); - } - } - } - + error = false; - + //Configure Presence - if(home.presence && home.presence.user && home.presence.user.length){ - + if (home.presence && home.presence.user && home.presence.user.length) { let valid_userTypes = ['MOTION', 'OCCUPANCY']; let activeUser = 0; - - home.presence.user.forEach(user => { - - if(user.active){ - - if(!user.name) { + + home.presence.user.forEach((user) => { + if (user.active) { + if (!user.name) { Logger.warn('There is no name configured for this user. This user will be skipped.', home.name); error = true; } - - if(!error){ - - const thisName = home.name + ' ' + user.name; - + + if (!error) { + const thisName = home.name + ' ' + user.name; + const uuid = UUIDGen.generate(thisName); - + if (devices.has(uuid)) { - - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', thisName); - + Logger.warn( + 'Multiple devices are configured with this name. Duplicate devices will be skipped.', + thisName + ); } else { - activeUser += 1; - + let config = { ...accessoryConfig }; - + config.name = thisName; - config.subtype = valid_userTypes.includes(user.accType) && user.accType === 'MOTION' - ? 'presence-motion' - : 'presence-occupancy'; + config.subtype = + valid_userTypes.includes(user.accType) && user.accType === 'MOTION' + ? 'presence-motion' + : 'presence-occupancy'; config.anyone = home.presence.anyone; - + config.model = config.subtype; config.serialNumber = hashCode(thisName); - + devices.set(uuid, config); - } - } - } - }); - + //Coinfigure Anyone Sensor - if(activeUser && home.presence.anyone){ - - const name = home.name + ' Anyone'; + if (activeUser && home.presence.anyone) { + const name = home.name + ' Anyone'; const uuid = UUIDGen.generate(name); - + if (devices.has(uuid)) { - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name); - } else { - - let config = { ...accessoryConfig }; - + let config = { ...accessoryConfig }; + config.name = name; - config.subtype = valid_userTypes.includes(config.accTypeAnyone) && config.accTypeAnyone === 'MOTION' - ? 'presence-motion' - : 'presence-occupancy'; + config.subtype = + valid_userTypes.includes(config.accTypeAnyone) && config.accTypeAnyone === 'MOTION' + ? 'presence-motion' + : 'presence-occupancy'; config.anyone = home.presence.anyone; - + config.model = config.subtype; config.serialNumber = hashCode(name); - + devices.set(uuid, config); - } - } - } - + error = false; - + //Configure Weather - if(home.weather){ - + if (home.weather) { //Configure Weather TemperatureSensor - if(home.weather.temperatureSensor){ - - const name = home.name + ' Weather'; + if (home.weather.temperatureSensor) { + const name = home.name + ' Weather'; const uuid = UUIDGen.generate(name); - + if (devices.has(uuid)) { - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name); - } else { - let config = { ...accessoryConfig }; - + config.name = name; config.subtype = 'weather-temperature'; - + config.model = 'Weather Temperature'; config.serialNumber = hashCode(name); - + devices.set(uuid, config); - } - } - + //Configure Weather SolarIntensity Lightbulb - if(home.weather.solarIntensity){ - - const name = home.name + ' Solar Intensity'; + if (home.weather.solarIntensity) { + const name = home.name + ' Solar Intensity'; const uuid = UUIDGen.generate(name); - + if (devices.has(uuid)) { - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name); - } else { - let config = { ...accessoryConfig }; - + config.name = name; - config.subtype = home.weather.accTypeSolarIntensity === 'SENSOR' - ? 'weather-lightsensor' - : 'weather-lightbulb'; + config.subtype = + home.weather.accTypeSolarIntensity === 'SENSOR' ? 'weather-lightsensor' : 'weather-lightbulb'; config.model = 'Solar Intensity'; config.serialNumber = hashCode(name); - + devices.set(uuid, config); - } - } - + //Configure Weather AirQuality Sensor - if(home.weather.airQuality && home.geolocation && home.geolocation.latitude && home.geolocation.longitude){ - - const name = home.name + ' Air Quality'; + if ( + home.weather.airQuality && + home.geolocation && + home.geolocation.latitude && + home.geolocation.longitude + ) { + const name = home.name + ' Air Quality'; const uuid = UUIDGen.generate(name); - + if (devices.has(uuid)) { - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name); - } else { - let config = { ...accessoryConfig }; - + config.name = name; config.subtype = 'weather-airquality'; config.latitude = home.geolocation.latitude; config.longitude = home.geolocation.longitude; - + config.model = 'Air Quality Sensor'; config.serialNumber = hashCode(name); - + devices.set(uuid, config); - } - } - } - + error = false; - + //Configure Extras - if(home.extras){ - - if(activeZones){ - + if (home.extras) { + if (activeZones) { let validSwitches = []; - + //Configure Central Switch - if(home.extras.centralSwitch){ - + if (home.extras.centralSwitch) { validSwitches.push({ name: 'Central', - sub: 'Central' + sub: 'Central', }); //Configure Boost Switch - if(home.extras.boostSwitch){ - + if (home.extras.boostSwitch) { validSwitches.push({ name: 'Boost', - sub: 'CentralBoost' + sub: 'CentralBoost', }); - } - + //Configure Shedule Switch - if(home.extras.sheduleSwitch){ - + if (home.extras.sheduleSwitch) { validSwitches.push({ name: 'Shedule', - sub: 'CentralShedule' + sub: 'CentralShedule', }); - } - + //Configure Turnoff Switch - if(home.extras.turnoffSwitch){ - + if (home.extras.turnoffSwitch) { validSwitches.push({ name: 'Off', - sub: 'CentralOff' + sub: 'CentralOff', }); - } - + //Configure Turnoff Switch - if(home.extras.dummySwitch){ - + if (home.extras.dummySwitch) { validSwitches.push({ name: 'Dummy', - sub: 'CentralDummy' + sub: 'CentralDummy', }); - } - } - - if(validSwitches.length){ - - const name = home.name + ' Central Switch'; + + if (validSwitches.length) { + const name = home.name + ' Central Switch'; const uuid = UUIDGen.generate(name); - + if (devices.has(uuid)) { - - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name); - + Logger.warn( + 'Multiple devices are configured with this name. Duplicate devices will be skipped.', + name + ); } else { - let config = { ...accessoryConfig }; - + config.name = name; config.subtype = 'extra-cntrlswitch'; - config.runningInformation = home.extras.runningInformation; - config.rooms = home.zones.filter(zne => zne && zne.id); + config.runningInformation = home.extras.runningInformation; + config.rooms = home.zones.filter((zne) => zne && zne.id); config.switches = validSwitches; config.model = 'Central Switch'; config.serialNumber = hashCode(name); - + devices.set(uuid, config); - } - } - } - + //Configure Presence Lock - if(home.extras.presenceLock){ - - const name = home.name + ' Presence Lock'; + if (home.extras.presenceLock) { + const name = home.name + ' Presence Lock'; const uuid = UUIDGen.generate(name); - + if (devices.has(uuid)) { - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name); - } else { - let config = { ...accessoryConfig }; - + config.name = name; - config.subtype = home.extras.accTypePresenceLock === 'ALARM' - ? 'extra-plock' - : 'extra-plockswitch'; - + config.subtype = home.extras.accTypePresenceLock === 'ALARM' ? 'extra-plock' : 'extra-plockswitch'; + config.model = 'Presence Lock'; config.serialNumber = hashCode(name); - + devices.set(uuid, config); - } - } - + //Configure Child Lock - if(home.extras.childLockSwitches){ - + if (home.extras.childLockSwitches) { let validSwitches = []; - - home.extras.childLockSwitches.forEach(childLock => { - - if(childLock.active){ - - if(!childLock.name) { - Logger.warn('There is no name configured for this child lock switch. This switch will be skipped.', home.name); + + home.extras.childLockSwitches.forEach((childLock) => { + if (childLock.active) { + if (!childLock.name) { + Logger.warn( + 'There is no name configured for this child lock switch. This switch will be skipped.', + home.name + ); error = true; } - - if(!error){ - - validSwitches.push(childLock); - + + if (!error) { + validSwitches.push(childLock); } - } - - }); - - if(validSwitches.length){ - + + if (validSwitches.length) { const name = home.name + ' Child Lock'; const uuid = UUIDGen.generate(name); - + if (devices.has(uuid)) { - - Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name); - + Logger.warn( + 'Multiple devices are configured with this name. Duplicate devices will be skipped.', + name + ); } else { - let config = { ...accessoryConfig }; - + config.name = name; config.subtype = 'extra-childswitch'; - config.childLocks = validSwitches; + config.childLocks = validSwitches; config.model = config.subtype; config.serialNumber = hashCode(name); - + devices.set(uuid, config); - } - } - } - } - - if(home.telegram && home.telegram.active && home.telegram.token && home.telegram.chatID){ - + + if (home.telegram && home.telegram.active && home.telegram.token && home.telegram.chatID) { const telegramConfig = home.telegram; telegramConfig.messages = home.telegram.messages || {}; - + const messages = {}; - + Object.keys(telegramConfig.messages) - .filter( msg => Object.keys(telegramConfig.messages[msg]).length ) - .map(msg => { + .filter((msg) => Object.keys(telegramConfig.messages[msg]).length) + .map((msg) => { messages[msg] = { - ...telegramConfig.messages[msg] + ...telegramConfig.messages[msg], }; }); - - telegram = new Telegram(telegramConfig, messages); - + + telegram = new Telegram(telegramConfig, messages); } else { - Logger.debug('Telegram is not or not correctly set up. Skip.'); - - } - + } + deviceHandler.set(home.name, accessoryConfig); - } - }); - - } - + } + return { config: config, devices: devices, deviceHandler: deviceHandler, - telegram: telegram + telegram: telegram, }; - }, - - store: async function(config, storePath){ - + + store: async function (config, storePath) { const configJSON = await fs.readJson(storePath + '/config.json'); - - for(const i in configJSON.platforms) - if(configJSON.platforms[i].platform === 'TadoPlatform') - configJSON.platforms[i] = config; - + + for (const i in configJSON.platforms) + if (configJSON.platforms[i].platform === 'TadoPlatform') configJSON.platforms[i] = config; + fs.writeJsonSync(storePath + '/config.json', configJSON, { spaces: 4 }); - - return; - - } -}; \ No newline at end of file + return; + }, +}; diff --git a/src/types/custom.js b/src/types/custom.js index 2025052..a169fb7 100644 --- a/src/types/custom.js +++ b/src/types/custom.js @@ -10,142 +10,142 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // AutoThermostats Characteristic /// ///////////////////////////////////////////////////////////////////////// - Characteristic.AutoThermostats = function() { + Characteristic.AutoThermostats = function () { Characteristic.call(this, 'Mode Auto', '12edece0-36c8-427f-895c-3b88ea186388'); this.setProps({ format: Characteristic.Formats.INT, maxValue: 100, minValue: 0, minStep: 1, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.AutoThermostats, Characteristic); Characteristic.AutoThermostats.UUID = '12edece0-36c8-427f-895c-3b88ea186388'; - + /// ///////////////////////////////////////////////////////////////////////// // ManualThermostats Characteristic /// ///////////////////////////////////////////////////////////////////////// - Characteristic.ManualThermostats = function() { + Characteristic.ManualThermostats = function () { Characteristic.call(this, 'Mode Manual', '2be09385-4dc3-4438-9fee-b5b2e0642004'); this.setProps({ format: Characteristic.Formats.INT, maxValue: 100, minValue: 0, minStep: 1, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.ManualThermostats, Characteristic); Characteristic.ManualThermostats.UUID = '2be09385-4dc3-4438-9fee-b5b2e0642004'; - + /// ///////////////////////////////////////////////////////////////////////// // OfflineThermostats Characteristic /// ///////////////////////////////////////////////////////////////////////// - Characteristic.OfflineThermostats = function() { + Characteristic.OfflineThermostats = function () { Characteristic.call(this, 'Mode Off', '93131984-615c-401b-84ac-54e22db492c6'); this.setProps({ format: Characteristic.Formats.INT, maxValue: 100, minValue: 0, minStep: 1, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.OfflineThermostats, Characteristic); Characteristic.OfflineThermostats.UUID = '93131984-615c-401b-84ac-54e22db492c6'; - + /// ///////////////////////////////////////////////////////////////////////// // OverallHeatDay Characteristic /// ///////////////////////////////////////////////////////////////////////// - Characteristic.OverallHeatDay = function() { + Characteristic.OverallHeatDay = function () { Characteristic.call(this, 'Activity Day', '43c89074-b70a-480c-8239-51697a9db445'); this.setProps({ format: Characteristic.Formats.FLOAT, maxValue: 99999, minValue: 0, minStep: 0.01, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.OverallHeatDay, Characteristic); Characteristic.OverallHeatDay.UUID = '43c89074-b70a-480c-8239-51697a9db445'; - + /// ///////////////////////////////////////////////////////////////////////// // OverallHeatMonth Characteristic /// ///////////////////////////////////////////////////////////////////////// - Characteristic.OverallHeatMonth = function() { + Characteristic.OverallHeatMonth = function () { Characteristic.call(this, 'Activity Month', '1874332a-d7dd-4e45-9d65-a4baa6d11121'); this.setProps({ format: Characteristic.Formats.FLOAT, maxValue: 99999, minValue: 0, minStep: 0.01, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.OverallHeatMonth, Characteristic); Characteristic.OverallHeatMonth.UUID = '1874332a-d7dd-4e45-9d65-a4baa6d11121'; - + /// ///////////////////////////////////////////////////////////////////////// // OverallHeatYear Characteristic /// ///////////////////////////////////////////////////////////////////////// - Characteristic.OverallHeatYear = function() { + Characteristic.OverallHeatYear = function () { Characteristic.call(this, 'Activity Year', 'd105b9f7-afe7-44a2-9cbe-f079ba499733'); this.setProps({ format: Characteristic.Formats.FLOAT, maxValue: 99999, minValue: 0, minStep: 0.01, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.OverallHeatYear, Characteristic); Characteristic.OverallHeatYear.UUID = 'd105b9f7-afe7-44a2-9cbe-f079ba499733'; - + /// ///////////////////////////////////////////////////////////////////////// // DelaySwitch Characteristic /// ///////////////////////////////////////////////////////////////////////// - Characteristic.DelaySwitch = function() { + Characteristic.DelaySwitch = function () { Characteristic.call(this, 'Delay', 'b7c9db1a-e54e-4f4f-b3b4-17a19b2c4631'); this.setProps({ format: Characteristic.Formats.BOOL, - perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.DelaySwitch, Characteristic); Characteristic.DelaySwitch.UUID = 'b7c9db1a-e54e-4f4f-b3b4-17a19b2c4631'; - + /// ///////////////////////////////////////////////////////////////////////// // DelayTimer Characteristic /// ///////////////////////////////////////////////////////////////////////// - Characteristic.DelayTimer = function() { + Characteristic.DelayTimer = function () { Characteristic.call(this, 'Timer', '2e4eb630-62ab-41fe-bcc1-ea5c3cf98508'); this.setProps({ format: Characteristic.Formats.INT, maxValue: 120, minValue: 0, minStep: 10, - perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.DelayTimer, Characteristic); Characteristic.DelayTimer.UUID = '2e4eb630-62ab-41fe-bcc1-ea5c3cf98508'; - + /// ///////////////////////////////////////////////////////////////////////// // Thermostat Service - /// ///////////////////////////////////////////////////////////////////////// - Service.Thermostat = function(displayName, subtype) { + /// ///////////////////////////////////////////////////////////////////////// + Service.Thermostat = function (displayName, subtype) { Service.call(this, displayName, '0000004A-0000-1000-8000-0026BB765291', subtype); - + // Required Characteristics this.addCharacteristic(Characteristic.CurrentHeatingCoolingState); this.addCharacteristic(Characteristic.TargetHeatingCoolingState); @@ -160,17 +160,16 @@ module.exports = { this.addOptionalCharacteristic(Characteristic.TargetRelativeHumidity); this.addOptionalCharacteristic(Characteristic.CoolingThresholdTemperature); this.addOptionalCharacteristic(Characteristic.HeatingThresholdTemperature); - }; inherits(Service.Thermostat, Service); Service.Thermostat.UUID = '0000004A-0000-1000-8000-0026BB765291'; - + /// ///////////////////////////////////////////////////////////////////////// // HeaterCooler Service - /// ///////////////////////////////////////////////////////////////////////// - Service.HeaterCooler = function(displayName, subtype) { + /// ///////////////////////////////////////////////////////////////////////// + Service.HeaterCooler = function (displayName, subtype) { Service.call(this, displayName, '000000BC-0000-1000-8000-0026BB765291', subtype); - + // Required Characteristics this.addCharacteristic(Characteristic.Active); this.addCharacteristic(Characteristic.CurrentHeaterCoolerState); @@ -187,17 +186,16 @@ module.exports = { this.addOptionalCharacteristic(Characteristic.CoolingThresholdTemperature); this.addOptionalCharacteristic(Characteristic.HeatingThresholdTemperature); this.addOptionalCharacteristic(Characteristic.TemperatureDisplayUnits); - }; inherits(Service.HeaterCooler, Service); Service.HeaterCooler.UUID = '000000BC-0000-1000-8000-0026BB765291'; - + /// ///////////////////////////////////////////////////////////////////////// // Faucet Service - /// ///////////////////////////////////////////////////////////////////////// - Service.Faucet = function(displayName, subtype) { + /// ///////////////////////////////////////////////////////////////////////// + Service.Faucet = function (displayName, subtype) { Service.call(this, displayName, '000000D7-0000-1000-8000-0026BB765291', subtype); - + // Required Characteristics this.addCharacteristic(Characteristic.Active); @@ -209,17 +207,16 @@ module.exports = { this.addOptionalCharacteristic(Characteristic.ServiceLabelIndex); this.addOptionalCharacteristic(Characteristic.SetDuration); this.addOptionalCharacteristic(Characteristic.StatusFault); - }; inherits(Service.Faucet, Service); Service.Faucet.UUID = '000000D7-0000-1000-8000-0026BB765291'; - + /// ///////////////////////////////////////////////////////////////////////// // Valve Service - /// ///////////////////////////////////////////////////////////////////////// - Service.Valve = function(displayName, subtype) { + /// ///////////////////////////////////////////////////////////////////////// + Service.Valve = function (displayName, subtype) { Service.call(this, displayName, '000000D0-0000-1000-8000-0026BB765291', subtype); - + // Required Characteristics this.addCharacteristic(Characteristic.Active); this.addCharacteristic(Characteristic.InUse); @@ -232,23 +229,22 @@ module.exports = { this.addOptionalCharacteristic(Characteristic.CurrentHeaterCoolerState); this.addOptionalCharacteristic(Characteristic.TargetHeaterCoolerState); this.addOptionalCharacteristic(Characteristic.HeatingThresholdTemperature); - }; inherits(Service.Valve, Service); Service.Valve.UUID = '000000D0-0000-1000-8000-0026BB765291'; - + /// ///////////////////////////////////////////////////////////////////////// // AirQuality Service - /// ///////////////////////////////////////////////////////////////////////// - Service.AirQuality = function(displayName, subtype) { + /// ///////////////////////////////////////////////////////////////////////// + Service.AirQuality = function (displayName, subtype) { Service.call(this, displayName, '0000008D-0000-1000-8000-0026BB765291', subtype); - + // Required Characteristics this.addCharacteristic(Characteristic.AirQuality); // Optional Characteristics this.addOptionalCharacteristic(Characteristic.Name); - + this.addOptionalCharacteristic(Characteristic.NitrogenDioxideDensity); this.addOptionalCharacteristic(Characteristic.OzoneDensity); this.addOptionalCharacteristic(Characteristic.PM10Density); @@ -256,15 +252,13 @@ module.exports = { this.addOptionalCharacteristic(Characteristic.SulphurDioxideDensity); this.addOptionalCharacteristic(Characteristic.VOCDensity); this.addOptionalCharacteristic(Characteristic.CarbonMonoxideLevel); - + this.addOptionalCharacteristic(Characteristic.StatusActive); this.addOptionalCharacteristic(Characteristic.StatusFault); this.addOptionalCharacteristic(Characteristic.StatusLowBattery); this.addOptionalCharacteristic(Characteristic.StatusTampered); - }; inherits(Service.AirQuality, Service); Service.AirQuality.UUID = '0000008D-0000-1000-8000-0026BB765291'; - - } + }, }; diff --git a/src/types/eve.js b/src/types/eve.js index 8886c78..2c3748f 100644 --- a/src/types/eve.js +++ b/src/types/eve.js @@ -9,13 +9,13 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // ResetTotal - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.ResetTotal = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.ResetTotal = function () { Characteristic.call(this, 'Reset Total', 'E863F112-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, unit: Characteristic.Units.SECONDS, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE], }); this.value = this.getDefaultValue(); }; @@ -24,12 +24,12 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // HistoryStatus - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.HistoryStatus = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.HistoryStatus = function () { Characteristic.call(this, 'History Status', 'E863F116-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.DATA, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE], }); this.value = this.getDefaultValue(); }; @@ -38,12 +38,12 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // HistoryEntries - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.HistoryEntries = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.HistoryEntries = function () { Characteristic.call(this, 'History Entries', 'E863F117-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.DATA, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE], }); this.value = this.getDefaultValue(); }; @@ -52,12 +52,12 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // HistoryRequest - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.HistoryRequest = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.HistoryRequest = function () { Characteristic.call(this, 'History Request', 'E863F11C-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.DATA, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE], }); this.value = this.getDefaultValue(); }; @@ -66,12 +66,12 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // SetTime - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.SetTime = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.SetTime = function () { Characteristic.call(this, 'Set Time', 'E863F121-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.DATA, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE], }); this.value = this.getDefaultValue(); }; @@ -80,13 +80,13 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // LastActivation - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.LastActivation = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.LastActivation = function () { Characteristic.call(this, 'Last Activation', 'E863F11A-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, unit: Characteristic.Units.SECONDS, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; @@ -95,12 +95,12 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // TimesOpened - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.TimesOpened = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.TimesOpened = function () { Characteristic.call(this, 'Times Opened', 'E863F129-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; @@ -109,13 +109,13 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // OpenDuration - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.OpenDuration = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.OpenDuration = function () { Characteristic.call(this, 'Open Duration', 'E863F118-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, unit: Characteristic.Units.SECONDS, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE], }); this.value = this.getDefaultValue(); }; @@ -124,73 +124,73 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // ClosedDuration - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.ClosedDuration = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.ClosedDuration = function () { Characteristic.call(this, 'Closed Duration', 'E863F119-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, unit: Characteristic.Units.SECONDS, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.ClosedDuration, Characteristic); Characteristic.ClosedDuration.UUID = 'E863F119-079E-48FF-8F27-9C2605A29F52'; - + /// ///////////////////////////////////////////////////////////////////////// // CurrentConsumption - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.CurrentConsumption = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.CurrentConsumption = function () { Characteristic.call(this, 'Current Consumption', 'E863F10D-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.FLOAT, unit: 'W', - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.CurrentConsumption, Characteristic); Characteristic.CurrentConsumption.UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; - + /// ///////////////////////////////////////////////////////////////////////// // TotalConsumption - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.TotalConsumption = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.TotalConsumption = function () { Characteristic.call(this, 'Total Consumption', 'E863F10C-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.FLOAT, unit: 'kWh', - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.TotalConsumption, Characteristic); Characteristic.TotalConsumption.UUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; - + /// ///////////////////////////////////////////////////////////////////////// // Volts - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.Volts = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.Volts = function () { Characteristic.call(this, 'Volts', 'E863F10A-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.FLOAT, unit: 'V', - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.Volts, Characteristic); Characteristic.Volts.UUID = 'E863F10A-079E-48FF-8F27-9C2605A29F52'; - + /// ///////////////////////////////////////////////////////////////////////// // Amperes - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.Amperes = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.Amperes = function () { Characteristic.call(this, 'Amperes', 'E863F126-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.FLOAT, unit: 'A', - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; @@ -199,41 +199,41 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // ValvePosition - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.ValvePosition = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.ValvePosition = function () { Characteristic.call(this, 'Valve Position', 'E863F12E-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT8, unit: Characteristic.Units.PERCENTAGE, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.ValvePosition, Characteristic); Characteristic.ValvePosition.UUID = 'E863F12E-079E-48FF-8F27-9C2605A29F52'; - + /// ///////////////////////////////////////////////////////////////////////// // ProgramCommand - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.ProgramCommand = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.ProgramCommand = function () { Characteristic.call(this, 'Program Command', 'E863F12C-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.DATA, - perms: [Characteristic.Perms.WRITE] + perms: [Characteristic.Perms.WRITE], }); this.value = this.getDefaultValue(); }; inherits(Characteristic.ProgramCommand, Characteristic); Characteristic.ProgramCommand.UUID = 'E863F12C-079E-48FF-8F27-9C2605A29F52'; - + /// ///////////////////////////////////////////////////////////////////////// // ProgramData - /// ///////////////////////////////////////////////////////////////////////// - Characteristic.ProgramData = function() { + /// ///////////////////////////////////////////////////////////////////////// + Characteristic.ProgramData = function () { Characteristic.call(this, 'Program Data', 'E863F12F-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.DATA, - perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], }); this.value = this.getDefaultValue(); }; @@ -242,10 +242,10 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // Outlet - /// ///////////////////////////////////////////////////////////////////////// - Service.Outlet = function(displayName, subtype) { + /// ///////////////////////////////////////////////////////////////////////// + Service.Outlet = function (displayName, subtype) { Service.call(this, displayName, '00000047-0000-1000-8000-0026BB765291', subtype); - + // Required Characteristics this.addCharacteristic(Characteristic.On); this.addCharacteristic(Characteristic.OutletInUse); @@ -258,15 +258,14 @@ module.exports = { // Optional Characteristics this.addOptionalCharacteristic(Characteristic.Name); - }; inherits(Service.Outlet, Service); Service.Outlet.UUID = '00000047-0000-1000-8000-0026BB765291'; - + /// ///////////////////////////////////////////////////////////////////////// // Thermostat - /// ///////////////////////////////////////////////////////////////////////// - Service.Thermostat = function(displayName, subtype) { + /// ///////////////////////////////////////////////////////////////////////// + Service.Thermostat = function (displayName, subtype) { Service.call(this, displayName, '0000004A-0000-1000-8000-0026BB765291', subtype); // Required Characteristics this.addCharacteristic(Characteristic.CurrentHeatingCoolingState); @@ -292,8 +291,8 @@ module.exports = { /// ///////////////////////////////////////////////////////////////////////// // ContactSensor - /// ///////////////////////////////////////////////////////////////////////// - Service.ContactSensor = function(displayName, subtype) { + /// ///////////////////////////////////////////////////////////////////////// + Service.ContactSensor = function (displayName, subtype) { Service.call(this, displayName, '00000080-0000-1000-8000-0026BB765291', subtype); // Required Characteristics this.addCharacteristic(Characteristic.ContactSensorState); @@ -313,11 +312,11 @@ module.exports = { }; inherits(Service.ContactSensor, Service); Service.ContactSensor.UUID = '00000080-0000-1000-8000-0026BB765291'; - + /// ///////////////////////////////////////////////////////////////////////// // MotionSensor - /// ///////////////////////////////////////////////////////////////////////// - Service.MotionSensor = function(displayName, subtype) { + /// ///////////////////////////////////////////////////////////////////////// + Service.MotionSensor = function (displayName, subtype) { Service.call(this, displayName, '00000085-0000-1000-8000-0026BB765291', subtype); // Required Characteristics this.addCharacteristic(Characteristic.MotionDetected); @@ -334,6 +333,5 @@ module.exports = { }; inherits(Service.MotionSensor, Service); Service.MotionSensor.UUID = '00000085-0000-1000-8000-0026BB765291'; - - } -}; \ No newline at end of file + }, +};