diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..902e474 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,15 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; + +export default [ + { files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } }, + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + }, + pluginJs.configs.recommended, +]; diff --git a/package-lock.json b/package-lock.json index 93eead2..860e757 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6530 +1,7825 @@ { "name": "api", - "version": "1.0.0", - "lockfileVersion": 1, + "version": "2.0.0", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@samverschueren/stream-to-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", - "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "packages": { + "": { + "name": "api", + "version": "2.0.0", + "dependencies": { + "aws-sdk": "2.1660.0", + "axios": "1.7.2", + "bcrypt-nodejs": "0.0.3", + "body-parser": "1.20.2", + "cors": "2.8.5", + "dotenv": "16.4.5", + "express": "4.19.2", + "form-data": "4.0.0", + "freemail": "1.7.0", + "google-auth-library": "9.11.0", + "helmet": "7.1.0", + "ip": "2.0.1", + "jimp": "0.22.12", + "jsonwebtoken": "9.0.2", + "lodash": "4.17.21", + "moment": "2.30.1", + "moment-timezone": "0.5.45", + "mongodb-uri": "0.9.7", + "mongoose": "8.5.1", + "morgan": "1.10.0", + "multer": "1.3.0", + "nodemailer": "6.9.14", + "now": "11.4.6", + "randomstring": "1.3.0", + "raven": "2.6.0", + "speakingurl": "14.0.1", + "validator": "13.12.0" + }, + "devDependencies": { + "@eslint/js": "^9.7.0", + "commitizen": "4.3.0", + "cross-env": "7.0.3", + "cz-conventional-changelog": "3.3.0", + "eslint": "^9.7.0", + "globals": "^15.8.0", + "gulp": "5.0.0", + "gulp-eslint-new": "^2.2.0", + "gulp-nodemon": "^2.2.1", + "husky": "9.1.1", + "lint-staged": "15.2.7", + "prettier": "3.3.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, - "requires": { - "any-observable": "^0.3.0" + "optional": true, + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6.9.0" } }, - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, - "requires": { - "acorn": "^3.0.4" + "optional": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.0.3.tgz", + "integrity": "sha512-2D3r4PKjoo59zBc2auodrSCaUnCSALCx54yveOFwwP/i2kfEAQrygwOleFWswLqK0UL/F9r07MFi5ev2ohyM4Q==", + "dev": true, + "optional": true, "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } + "@commitlint/types": "^19.0.3", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" } }, - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "node_modules/@commitlint/execute-rule": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.0.0.tgz", + "integrity": "sha512-mtsdpY1qyWgAO/iOK0L6gSGeR7GFcdW7tIjcNFxcWkfLDF5qVbPHKuGATFqRMsxcO8OUKNj0+3WOHB7EHm4Jdw==", + "dev": true, + "optional": true, + "engines": { + "node": ">=v18" } }, - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", - "dev": true + "node_modules/@commitlint/load": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.2.0.tgz", + "integrity": "sha512-XvxxLJTKqZojCxaBQ7u92qQLFMMZc4+p9qrIq/9kJDy8DOrEa7P1yx7Tjdc2u2JxIalqT4KOGraVgCE7eCYJyQ==", + "dev": true, + "optional": true, + "dependencies": { + "@commitlint/config-validator": "^19.0.3", + "@commitlint/execute-rule": "^19.0.0", + "@commitlint/resolve-extends": "^19.1.0", + "@commitlint/types": "^19.0.3", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^5.0.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } }, - "ansi-align": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "requires": { - "string-width": "^2.0.0" + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.1.0.tgz", + "integrity": "sha512-z2riI+8G3CET5CPgXJPlzftH+RiWYLMYv4C9tSLdLXdr6pBNimSKukYP9MS27ejmscqCTVA4almdLh0ODD2KYg==", + "dev": true, + "optional": true, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "@commitlint/config-validator": "^19.0.3", + "@commitlint/types": "^19.0.3", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" } }, - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", - "dev": true + "node_modules/@commitlint/types": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.0.3.tgz", + "integrity": "sha512-tpyc+7i6bPG9mvaBbtKUeghfyZSDgWquIDfMgqYtTbmZ9Y9VzEm2je9EYcQ0aoz5o7NvGS+rcDec93yO08MHYA==", + "dev": true, + "optional": true, + "dependencies": { + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "requires": { - "ansi-wrap": "0.1.0" + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", - "dev": true + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } }, - "any-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", - "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", - "dev": true + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/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": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "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" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "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/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "append-field": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz", - "integrity": "sha1-bdxY+gg8e8VF08WZWygwzCNm1Eo=" + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/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 }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@eslint/js": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", + "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", "dev": true, - "requires": { - "sprintf-js": "~1.0.2" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, - "requires": { - "arr-flatten": "^1.0.1" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "arr-flatten": { + "node_modules/@gulpjs/messages": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true + "resolved": "https://registry.npmjs.org/@gulpjs/messages/-/messages-1.1.0.tgz", + "integrity": "sha512-Ys9sazDatyTgZVb4xPlDufLweJ/Os2uHWOv+Caxvy2O85JcnT4M3vc73bi8pdLWlv3fdWQz3pdI9tVwo8rQQSg==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true + "node_modules/@gulpjs/to-absolute-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@gulpjs/to-absolute-glob/-/to-absolute-glob-4.0.0.tgz", + "integrity": "sha512-kjotm7XJrJ6v+7knhPaRgaT6q8F8K2jiafwYdNHLzmV0uGLuZY43FK6smNSHUPrhq5kX2slCUy+RGG/xGqmIKA==", + "dev": true, + "dependencies": { + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=10.13.0" + } }, - "array-each": { + "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", - "dev": true + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true + "node_modules/@jimp/bmp": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.12.tgz", + "integrity": "sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "bmp-js": "^0.1.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "array-uniq": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz", - "integrity": "sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0=" + "node_modules/@jimp/core": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.12.tgz", + "integrity": "sha512-l0RR0dOPyzMKfjUW1uebzueFEDtCOj9fN6pyTYWWOM/VS4BciXQ1VVrJs8pO3kycGYZxncRKhCoygbNr8eEZQA==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "any-base": "^1.1.0", + "buffer": "^5.2.0", + "exif-parser": "^0.1.12", + "file-type": "^16.5.4", + "isomorphic-fetch": "^3.0.0", + "pixelmatch": "^4.0.2", + "tinycolor2": "^1.6.0" + } }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true + "node_modules/@jimp/core/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" + "node_modules/@jimp/custom": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz", + "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==", + "dependencies": { + "@jimp/core": "^0.22.12" } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "node_modules/@jimp/gif": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.22.12.tgz", + "integrity": "sha512-y6BFTJgch9mbor2H234VSjd9iwAhaNf/t3US5qpYIs0TSbAvM02Fbc28IaDETj9+4YB4676sz4RcN/zwhfu1pg==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "gifwrap": "^0.10.1", + "omggif": "^1.0.9" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true + "node_modules/@jimp/jpeg": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.12.tgz", + "integrity": "sha512-Rq26XC/uQWaQKyb/5lksCTCxXhtY01NJeBN+dQv5yNYedN0i7iYu+fXEoRsfaJ8xZzjoANH8sns7rVP4GE7d/Q==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "jpeg-js": "^0.4.4" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "requires": { - "lodash": "^4.17.10" + "node_modules/@jimp/plugin-blit": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.12.tgz", + "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==", + "dependencies": { + "@jimp/utils": "^0.22.12" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blur": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.12.tgz", + "integrity": "sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==", "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - } + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true + "node_modules/@jimp/plugin-circle": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.22.12.tgz", + "integrity": "sha512-SWVXx1yiuj5jZtMijqUfvVOJBwOifFn0918ou4ftoHgegc5aHWW5dZbYPjvC9fLpvz7oSlptNl2Sxr1zwofjTg==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "node_modules/@jimp/plugin-color": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.12.tgz", + "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "tinycolor2": "^1.6.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true + "node_modules/@jimp/plugin-contain": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.22.12.tgz", + "integrity": "sha512-Eo3DmfixJw3N79lWk8q/0SDYbqmKt1xSTJ69yy8XLYQj9svoBbyRpSnHR+n9hOw5pKXytHwUW6nU4u1wegHNoQ==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } }, - "aws-sdk": { - "version": "2.94.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.94.0.tgz", - "integrity": "sha1-cEPePvjCTLarS/I18I2H2EFz4XQ=", - "requires": { - "buffer": "4.9.1", - "crypto-browserify": "1.0.9", - "events": "^1.1.1", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.0.1", - "xml2js": "0.4.17", - "xmlbuilder": "4.2.1" + "node_modules/@jimp/plugin-cover": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.22.12.tgz", + "integrity": "sha512-z0w/1xH/v/knZkpTNx+E8a7fnasQ2wHG5ze6y5oL2dhH1UufNua8gLQXlv8/W56+4nJ1brhSd233HBJCo01BXA==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" } }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "node_modules/@jimp/plugin-crop": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz", + "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "aws4": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", - "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" + "node_modules/@jimp/plugin-displace": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.22.12.tgz", + "integrity": "sha512-qpRM8JRicxfK6aPPqKZA6+GzBwUIitiHaZw0QrJ64Ygd3+AsTc7BXr+37k2x7QcyCvmKXY4haUrSIsBug4S3CA==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "axios": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", - "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", - "requires": { - "follow-redirects": "^1.3.0", - "is-buffer": "^1.1.5" + "node_modules/@jimp/plugin-dither": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.22.12.tgz", + "integrity": "sha512-jYgGdSdSKl1UUEanX8A85v4+QUm+PE8vHFwlamaKk89s+PXQe7eVE3eNeSZX4inCq63EHL7cX580dMqkoC3ZLw==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "node_modules/@jimp/plugin-fisheye": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.22.12.tgz", + "integrity": "sha512-LGuUTsFg+fOp6KBKrmLkX4LfyCy8IIsROwoUvsUPKzutSqMJnsm3JGDW2eOmWIS/jJpPaeaishjlxvczjgII+Q==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "babel-polyfill": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", - "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "core-js": "^2.4.0", - "regenerator-runtime": "^0.10.0" + "node_modules/@jimp/plugin-flip": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.22.12.tgz", + "integrity": "sha512-m251Rop7GN8W0Yo/rF9LWk6kNclngyjIJs/VXHToGQ6EGveOSTSQaX2Isi9f9lCDLxt+inBIb7nlaLLxnvHX8Q==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-rotate": ">=0.3.5" } }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "node_modules/@jimp/plugin-gaussian": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.22.12.tgz", + "integrity": "sha512-sBfbzoOmJ6FczfG2PquiK84NtVGeScw97JsCC3rpQv1PHVWyW+uqWFF53+n3c8Y0P2HWlUjflEla2h/vWShvhg==", + "dependencies": { + "@jimp/utils": "^0.22.12" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-invert": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.22.12.tgz", + "integrity": "sha512-N+6rwxdB+7OCR6PYijaA/iizXXodpxOGvT/smd/lxeXsZ/empHmFFFJ/FaXcYh19Tm04dGDaXcNF/dN5nm6+xQ==", "dependencies": { - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - } + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "node_modules/@jimp/plugin-mask": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.22.12.tgz", + "integrity": "sha512-4AWZg+DomtpUA099jRV8IEZUfn1wLv6+nem4NRJC7L/82vxzLCgXKTxvNvBcNmJjT9yS1LAAmiJGdWKXG63/NA==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "node_modules/@jimp/plugin-normalize": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.22.12.tgz", + "integrity": "sha512-0So0rexQivnWgnhacX4cfkM2223YdExnJTTy6d06WbkfZk5alHUx8MM3yEzwoCN0ErO7oyqEWRnEkGC+As1FtA==", + "dependencies": { + "@jimp/utils": "^0.22.12" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-print": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.22.12.tgz", + "integrity": "sha512-c7TnhHlxm87DJeSnwr/XOLjJU/whoiKYY7r21SbuJ5nuH+7a78EW1teOaj5gEr2wYEd7QtkFqGlmyGXY/YclyQ==", "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "@jimp/utils": "^0.22.12", + "load-bmfont": "^1.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5" } }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + "node_modules/@jimp/plugin-resize": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz", + "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "basic-auth": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", - "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" + "node_modules/@jimp/plugin-rotate": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.12.tgz", + "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } }, - "bcrypt-nodejs": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz", - "integrity": "sha1-xgkX8m3CNWYVZsaBBhwwPCsohCs=" + "node_modules/@jimp/plugin-scale": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.12.tgz", + "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" + "node_modules/@jimp/plugin-shadow": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.22.12.tgz", + "integrity": "sha512-FX8mTJuCt7/3zXVoeD/qHlm4YH2bVqBuWQHXSuBK054e7wFRnRnbSLPUqAwSeYP3lWqpuQzJtgiiBxV3+WWwTg==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blur": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" } }, - "beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", - "dev": true + "node_modules/@jimp/plugin-threshold": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.22.12.tgz", + "integrity": "sha512-4x5GrQr1a/9L0paBC/MZZJjjgjxLYrqSmWd+e+QfAEPvmRxdRoQ5uKEuNgXnm9/weHQBTnQBQsOY2iFja+XGAw==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-color": ">=0.8.0", + "@jimp/plugin-resize": ">=0.8.0" + } }, - "bignumber.js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.4.0.tgz", - "integrity": "sha1-g4qZLan51zfg9LLbC+YrsJ3Qxeg=" + "node_modules/@jimp/plugins": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.22.12.tgz", + "integrity": "sha512-yBJ8vQrDkBbTgQZLty9k4+KtUQdRjsIDJSPjuI21YdVeqZxYywifHl4/XWILoTZsjTUASQcGoH0TuC0N7xm3ww==", + "dependencies": { + "@jimp/plugin-blit": "^0.22.12", + "@jimp/plugin-blur": "^0.22.12", + "@jimp/plugin-circle": "^0.22.12", + "@jimp/plugin-color": "^0.22.12", + "@jimp/plugin-contain": "^0.22.12", + "@jimp/plugin-cover": "^0.22.12", + "@jimp/plugin-crop": "^0.22.12", + "@jimp/plugin-displace": "^0.22.12", + "@jimp/plugin-dither": "^0.22.12", + "@jimp/plugin-fisheye": "^0.22.12", + "@jimp/plugin-flip": "^0.22.12", + "@jimp/plugin-gaussian": "^0.22.12", + "@jimp/plugin-invert": "^0.22.12", + "@jimp/plugin-mask": "^0.22.12", + "@jimp/plugin-normalize": "^0.22.12", + "@jimp/plugin-print": "^0.22.12", + "@jimp/plugin-resize": "^0.22.12", + "@jimp/plugin-rotate": "^0.22.12", + "@jimp/plugin-scale": "^0.22.12", + "@jimp/plugin-shadow": "^0.22.12", + "@jimp/plugin-threshold": "^0.22.12", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true + "node_modules/@jimp/png": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.22.12.tgz", + "integrity": "sha512-Mrp6dr3UTn+aLK8ty/dSKELz+Otdz1v4aAXzV5q53UDD2rbB5joKVJ/ChY310B+eRzNxIovbUF1KVrUsYdE8Hg==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "pngjs": "^6.0.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + "node_modules/@jimp/tiff": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.12.tgz", + "integrity": "sha512-E1LtMh4RyJsoCAfAkBRVSYyZDTtLq9p9LUiiYP0vPtXyxX4BiYBUYihTLSBlCQg5nF2e4OpQg7SPrLdJ66u7jg==", + "dependencies": { + "utif2": "^4.0.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "bmp-js": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.0.3.tgz", - "integrity": "sha1-ZBE+nHzxICs3btYHvzBibr5XsYo=" - }, - "body-parser": { - "version": "1.17.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz", - "integrity": "sha1-+IkqvI+eYn1Crtr7yma/WrmRBO4=", - "requires": { - "bytes": "2.4.0", - "content-type": "~1.0.2", - "debug": "2.6.7", - "depd": "~1.1.0", - "http-errors": "~1.6.1", - "iconv-lite": "0.4.15", - "on-finished": "~2.3.0", - "qs": "6.4.0", - "raw-body": "~2.2.0", - "type-is": "~1.6.15" + "node_modules/@jimp/types": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.12.tgz", + "integrity": "sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA==", + "dependencies": { + "@jimp/bmp": "^0.22.12", + "@jimp/gif": "^0.22.12", + "@jimp/jpeg": "^0.22.12", + "@jimp/png": "^0.22.12", + "@jimp/tiff": "^0.22.12", + "timm": "^1.6.1" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/utils": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz", + "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } + "regenerator-runtime": "^0.13.3" } }, - "boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", - "dev": true, - "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "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" - } - }, - "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" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "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" - } - } + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", + "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==", + "dependencies": { + "sparse-bitfield": "^3.0.3" } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" } }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" + "engines": { + "node": ">= 8" } }, - "bson": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.9.tgz", - "integrity": "sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg==" - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" } }, - "buffer-equal": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", - "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=" + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, - "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/@types/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "node_modules/@types/eslint": { + "version": "8.56.11", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.11.tgz", + "integrity": "sha512-sVBpJMf7UPo/wGecYOpk2aQya2VUGeHhe38WG7/mN5FufNSubf5VT9Uh9Uyp8/eLJpu1/tuhJ/qTo4mhSB4V4Q==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, - "busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", - "requires": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" } }, - "bytes": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", - "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "@types/webidl-conversions": "*" } }, - "cachedir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-1.3.0.tgz", - "integrity": "sha512-O1ji32oyON9laVPJL1IZ5bmwd2cB46VfpxkDequezH+15FDzzVddEyrGEeX4WusDSqKxdyFdDQDEG1yo1GoWkg==", - "dev": true, - "requires": { - "os-homedir": "^1.0.1" + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" } }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, - "requires": { - "callsites": "^2.0.0" + "bin": { + "acorn": "bin/acorn" }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - } + "engines": { + "node": ">=0.4.0" } }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "requires": { - "callsites": "^0.2.0" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } }, - "camelize": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", - "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } }, - "capture-stack-trace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", - "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", - "dev": true + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true + "node_modules/ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "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, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, "dependencies": { - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "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-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - } + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" } }, - "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", - "dev": true + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true + "node_modules/any-base": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz", + "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==" }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", - "dev": true - }, - "cli-cursor": { + "node_modules/append-buffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", "dev": true, - "requires": { - "restore-cursor": "^1.0.1" + "dependencies": { + "buffer-equal": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "node_modules/append-buffer/node_modules/buffer-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", "dev": true, - "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" + "engines": { + "node": ">=0.4" }, - "dependencies": { - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true + "node_modules/append-field": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz", + "integrity": "sha1-bdxY+gg8e8VF08WZWygwzCNm1Eo=" }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "engines": { + "node": ">=0.10.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==", + "node_modules/arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", "dev": true, - "requires": { - "color-name": "1.1.3" + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "requires": { - "delayed-stream": "~1.0.0" + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "node_modules/arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "commitizen": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-2.10.1.tgz", - "integrity": "sha1-jDld7zSolfTpSVLC78PJ60w2g70=", - "dev": true, - "requires": { - "cachedir": "^1.1.0", - "chalk": "1.1.3", - "cz-conventional-changelog": "2.0.0", - "dedent": "0.6.0", - "detect-indent": "4.0.0", - "find-node-modules": "1.0.4", - "find-root": "1.0.0", - "fs-extra": "^1.0.0", - "glob": "7.1.1", - "inquirer": "1.2.3", - "lodash": "4.17.5", - "minimist": "1.2.0", - "opencollective": "1.0.3", - "path-exists": "2.1.0", - "shelljs": "0.7.6", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "cz-conventional-changelog": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-2.0.0.tgz", - "integrity": "sha1-Val5r9/pXnAkh50qD1kkYwFwtTM=", - "dev": true, - "requires": { - "conventional-commit-types": "^2.0.0", - "lodash.map": "^4.5.1", - "longest": "^1.0.1", - "pad-right": "^0.2.2", - "right-pad": "^1.0.1", - "word-wrap": "^1.0.3" - } - }, - "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", - "dev": true - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "engines": { + "node": ">=0.10.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 + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - }, + "node_modules/array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", + "dev": true, "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "node_modules/array-initial/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true, - "requires": { - "dot-prop": "^4.1.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" + "engines": { + "node": ">=0.10.0" } }, - "connect": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.2.tgz", - "integrity": "sha1-aU6NIGgb/kkCgsiriGvpjwn0L+c=", - "requires": { - "debug": "2.6.7", - "finalhandler": "1.0.3", - "parseurl": "~1.3.1", - "utils-merge": "1.0.0" - }, + "node_modules/array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "finalhandler": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.3.tgz", - "integrity": "sha1-70fneVDpmXgOhgIqVg4yF+DQzIk=", - "requires": { - "debug": "2.6.7", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.1", - "statuses": "~1.3.1", - "unpipe": "~1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "content-security-policy-builder": { + "node_modules/array-slice": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-1.1.0.tgz", - "integrity": "sha1-2R8bB2I2wRmFDH3umSS/VeBXcrM=", - "requires": { - "dashify": "^0.2.0" + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "conventional-commit-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-2.3.0.tgz", - "integrity": "sha512-6iB39PrcGYdz0n3z31kj6/Km6mK9hm9oMRhwcLnKxE7WNoeRKZbTAobliKrbYZ5jqyCvtcVEfjCiaEzhL3AVmQ==", - "dev": true - }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", - "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "node_modules/array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "dev": true, + "dependencies": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } }, - "cors": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz", - "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=", - "requires": { - "object-assign": "^4", - "vary": "^1" + "node_modules/array-sort/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "dependencies": { - "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" - } - } + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true, - "requires": { - "capture-stack-trace": "^1.0.0" + "engines": { + "node": ">=0.10.0" } }, - "cross-env": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.0.5.tgz", - "integrity": "sha1-Q4PTZNlmCHPdGFs5ivO/717//vM=", + "node_modules/async-done": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-2.0.0.tgz", + "integrity": "sha512-j0s3bzYq9yKIVLKGE/tWlCpa3PfFLcrDZLTSVdnnCTGagXuXBJO4SsY9Xdk/fQBirCkH4evW5xOeJXqlAQFdsw==", "dev": true, - "requires": { - "cross-spawn": "^5.1.0", - "is-windows": "^1.0.0" - }, "dependencies": { - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - } + "end-of-stream": "^1.4.4", + "once": "^1.4.0", + "stream-exhaust": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" } }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "node_modules/async-each": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", + "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + "node_modules/async-settle": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-2.0.0.tgz", + "integrity": "sha512-Obu/KE8FurfQRN6ODdHN9LuXqwC+JFIM9NRyZqJJ4ZfLJmIYN9Rg0/kb+wF70VV5+fJusTMQlJ1t5rF7J/ETdg==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } }, - "crypto-browserify": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz", - "integrity": "sha1-zFRJaF37hesRyYKKzHy4erW7/MA=" + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "crypto-random-string": { + "node_modules/at-least-node": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", - "dev": true - }, - "cz-conventional-changelog": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-2.1.0.tgz", - "integrity": "sha1-L0vHOQ4yROTfKT5ro1Hkx0Cnx2Q=", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, - "requires": { - "conventional-commit-types": "^2.0.0", - "lodash.map": "^4.5.1", - "longest": "^1.0.1", - "right-pad": "^1.0.1", - "word-wrap": "^1.0.3" + "engines": { + "node": ">= 4.0.0" } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" } }, - "dasherize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz", - "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg=" - }, - "dashify": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dashify/-/dashify-0.2.2.tgz", - "integrity": "sha1-agdBWgHJH69KMuONnfunH2HLIP4=" - }, - "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", - "dev": true + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", - "dev": true + "node_modules/aws-sdk": { + "version": "2.1660.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1660.0.tgz", + "integrity": "sha512-nyCEm6J4exq4gxeK5/LB5Q9unQTzFy6fbFHnrrmJZvp1KnRbJ10W2UtwQmeibPAz9b4w+RTKJMe6QEZ38eXeqA==", + "hasInstallScript": true, + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", "dev": true }, - "dedent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.6.0.tgz", - "integrity": "sha1-Dm2o8M5Sg471zsXI+TlrDBtko8s=", - "dev": true + "node_modules/bach": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bach/-/bach-2.0.1.tgz", + "integrity": "sha512-A7bvGMGiTOxGMpNupYl9HQTf0FFDNF4VCmks4PJpFyN1AX2pdKuxuwdvUz2Hu388wcgp+OvGFNsumBfFNkR7eg==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0", + "async-settle": "^2.0.0", + "now-and-later": "^3.0.0" + }, + "engines": { + "node": ">=10.13.0" + } }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "node_modules/bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", + "dev": true, + "optional": true }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, - "requires": { - "clone": "^1.0.2" + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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" + } + ] }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } }, - "deprecated": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", - "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", - "dev": true + "node_modules/basic-auth/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==" }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "node_modules/bcrypt-nodejs": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz", + "integrity": "sha1-xgkX8m3CNWYVZsaBBhwwPCsohCs=", + "deprecated": "bcrypt-nodejs is no longer actively maintained. Please use bcrypt or bcryptjs. See https://github.com/kelektiv/node.bcrypt.js/wiki/bcrypt-vs-brypt.js to learn more about these two options" }, - "detect-file": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz", - "integrity": "sha1-STXe39lIhkjgBrASlWbpOGcR6mM=", - "dev": true, - "requires": { - "fs-exists-sync": "^0.1.0" + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" } }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, - "requires": { - "repeating": "^2.0.0" + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "dicer": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", - "requires": { - "readable-stream": "1.1.x", - "streamsearch": "0.1.2" + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" } }, - "dns-prefetch-control": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz", - "integrity": "sha1-YN20V3dOF48flBXwyrsOhbCzALI=" - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, - "requires": { - "esutils": "^2.0.2" + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "dom-walk": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", - "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } }, - "dont-sniff-mimetype": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz", - "integrity": "sha1-WTKJDcn04vGeXrAqIAJuXl78j1g=" + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "node_modules/bl/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "requires": { - "is-obj": "^1.0.0" + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "dotenv": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", - "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=" + "node_modules/bmp-js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", + "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==" }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "node_modules/body-parser/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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, - "requires": { - "readable-stream": "~1.1.9" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "node_modules/bson": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", + "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "engines": { + "node": ">=16.20.1" } }, - "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" + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "node_modules/buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==", + "engines": { + "node": ">=0.4.0" + } }, - "elegant-spinner": { + "node_modules/buffer-equal-constant-time": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", - "dev": true + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dev": true, - "requires": { - "iconv-lite": "~0.4.13" + "node_modules/busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==", + "dependencies": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" } }, - "end-of-stream": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", - "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, - "requires": { - "once": "~1.3.0" - }, "dependencies": { - "once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", - "dev": true, - "requires": { - "wrappy": "1" - } - } + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "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==", + "node_modules/cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", "dev": true, - "requires": { - "is-arrayish": "^0.2.1" + "engines": { + "node": ">=6" } }, - "es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "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" + } }, - "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 + "node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/centra": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", + "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", + "dependencies": { + "follow-redirects": "^1.15.6" + } }, - "eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "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, - "requires": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", - "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.4", - "esquery": "^1.0.0", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^1.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.3.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", - "table": "4.0.2", - "text-table": "~0.2.0" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "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" - } - }, - "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" - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "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" - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - } + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "eslint-config-semistandard": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-semistandard/-/eslint-config-semistandard-12.0.1.tgz", - "integrity": "sha512-4zaPW5uRFasf2uRZkE19Y+W84KBV3q+oyWYOsgUN+5DQXE5HCsh7ZxeWDXxozk7NPycGm0kXcsJzLe5GZ1jCeg==", + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, - "eslint-config-standard": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", - "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", - "dev": true + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "engines": { + "node": "*" + } }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.0" + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/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": { - "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 - } + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "eslint-module-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", - "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, - "requires": { - "debug": "^2.6.8", - "pkg-dir": "^2.0.0" + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, "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 - } + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" } }, - "eslint-plugin-import": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.10.0.tgz", - "integrity": "sha1-+gkIPVp1KI35xsfQn+EiVZhWVec=", + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, - "requires": { - "builtin-modules": "^1.1.1", - "contains-path": "^0.1.0", - "debug": "^2.6.8", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", - "read-pkg-up": "^2.0.0" + "engines": { + "node": ">=6" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, "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": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "eslint-plugin-node": { + "node_modules/cli-truncate/node_modules/ansi-regex": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz", - "integrity": "sha512-Q/Cc2sW1OAISDS+Ji6lZS2KV4b7ueA/WydVWd1BECTQwVvfQy5JAi3glhINoKzoMnfnuRgNP+ZWKrGAbp3QDxw==", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, - "requires": { - "ignore": "^3.3.6", - "minimatch": "^3.0.4", - "resolve": "^1.3.3", - "semver": "^5.4.1" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "eslint-plugin-promise": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz", - "integrity": "sha512-2WO+ZFh7vxUKRfR0cOIMrWgYKdR6S1AlOezw6pC52B6oYpd5WFghN+QHxvrRdZMtbo8h3dfUZ2o1rWb0UPbKtg==", + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", "dev": true }, - "eslint-plugin-standard": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.1.0.tgz", - "integrity": "sha512-fVcdyuKRr0EZ4fjWl3c+gp1BANFJD1+RaWa2UPYfMZ6jCtp5RG00kSaXnK/dE5sYzt4kaWJ9qdxqUfc0d9kX0w==", - "dev": true - }, - "eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true - }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, - "requires": { - "estraverse": "^4.0.0" + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", "dev": true, - "requires": { - "estraverse": "^4.1.0" + "engines": { + "node": ">=0.8" } }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true + "node_modules/clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", "dev": true }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "event-stream": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz", - "integrity": "sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g==", + "node_modules/cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", "dev": true, - "requires": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" } }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "node_modules/cloneable-readable/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "exif-parser": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", - "integrity": "sha1-WKnS1ywCwfbwKg70qRZicrd2CSI=" - }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "node_modules/cloneable-readable/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==", "dev": true }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "node_modules/cloneable-readable/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", "dev": true, - "requires": { - "fill-range": "^2.1.0" + "engines": { + "node": ">=0.10.0" } }, - "expand-tilde": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=", + "node_modules/collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", "dev": true, - "requires": { - "os-homedir": "^1.0.1" - } - }, - "expect-ct": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/expect-ct/-/expect-ct-0.1.0.tgz", - "integrity": "sha1-UnNWeN4YUwiQ2Ne5XwrGNkCVgJQ=" - }, - "express": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.15.3.tgz", - "integrity": "sha1-urZdDwOqgMNYQIly/HAPkWlEtmI=", - "requires": { - "accepts": "~1.3.3", - "array-flatten": "1.1.1", - "content-disposition": "0.5.2", - "content-type": "~1.0.2", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.7", - "depd": "~1.1.0", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "etag": "~1.8.0", - "finalhandler": "~1.0.3", - "fresh": "0.5.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.1", - "path-to-regexp": "0.1.7", - "proxy-addr": "~1.1.4", - "qs": "6.4.0", - "range-parser": "~1.2.0", - "send": "0.15.3", - "serve-static": "1.12.3", - "setprototypeof": "1.0.3", - "statuses": "~1.3.1", - "type-is": "~1.6.15", - "utils-merge": "1.0.0", - "vary": "~1.1.1" - }, "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "external-editor": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz", - "integrity": "sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=", + "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, - "requires": { - "extend": "^3.0.0", - "spawn-sync": "^1.0.15", - "tmp": "^0.0.29" + "dependencies": { + "color-name": "1.1.3" } }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true, - "requires": { - "is-extglob": "^1.0.0" + "bin": { + "color-support": "bin.js" } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true }, - "fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true, - "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" + "engines": { + "node": ">=0.1.90" } }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "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" + } }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "engines": { + "node": ">=18" + } }, - "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/commitizen": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.0.tgz", + "integrity": "sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==", + "dev": true, + "dependencies": { + "cachedir": "2.3.0", + "cz-conventional-changelog": "3.3.0", + "dedent": "0.7.0", + "detect-indent": "6.1.0", + "find-node-modules": "^2.1.2", + "find-root": "1.1.0", + "fs-extra": "9.1.0", + "glob": "7.2.3", + "inquirer": "8.2.5", + "is-utf8": "^0.2.1", + "lodash": "4.17.21", + "minimist": "1.2.7", + "strip-bom": "4.0.0", + "strip-json-comments": "3.1.1" + }, + "bin": { + "commitizen": "bin/commitizen", + "cz": "bin/git-cz", + "git-cz": "bin/git-cz" + }, + "engines": { + "node": ">= 12" + } }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "node_modules/commitizen/node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "node_modules/commitizen/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "engines": { + "node": ">=8" } }, - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "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 }, - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "dev": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, - "finalhandler": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", - "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.3.1", - "unpipe": "~1.0.0" - }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "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=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "find-index": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", - "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", - "dev": true + "node_modules/concat-stream/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==" }, - "find-node-modules": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-1.0.4.tgz", - "integrity": "sha1-tt6zzMtpnIcDdne87eLF9YYrJVA=", - "dev": true, - "requires": { - "findup-sync": "0.4.2", - "merge": "^1.2.0" + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "find-parent-dir": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", - "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/conventional-commit-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", + "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", "dev": true }, - "find-root": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.0.0.tgz", - "integrity": "sha1-li/yEaqyXGUg/u641ih/j26VgHo=", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, - "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" + "node_modules/cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "engines": { + "node": ">= 0.6" } }, - "findup-sync": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.2.tgz", - "integrity": "sha1-qBF9D3MST1pFRoOVef5S1xKfteU=", + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true, - "requires": { - "detect-file": "^0.1.0", - "is-glob": "^2.0.1", - "micromatch": "^2.3.7", - "resolve-dir": "^0.1.0" + "engines": { + "node": ">=0.10.0" } }, - "fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "node_modules/copy-props": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-4.0.0.tgz", + "integrity": "sha512-bVWtw1wQLzzKiYROtvNlbJgxgBYt2bMJpkCbKmXM3xyijvcjjWXEk5nyrrT3bgJ7ODb19ZohE2T0Y3FgNPyoTw==", "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - }, "dependencies": { - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - } + "each-props": "^3.0.0", + "is-plain-object": "^5.0.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "first-chunk-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", - "dev": true + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", - "dev": true + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } }, - "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, - "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" + "optional": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "follow-redirects": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", - "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", - "requires": { - "debug": "^3.0.0" + "node_modules/cosmiconfig-typescript-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz", + "integrity": "sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==", + "dev": true, + "optional": true, + "dependencies": { + "jiti": "^1.19.1" + }, + "engines": { + "node": ">=v16" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=8.2", + "typescript": ">=4" } }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true + "node_modules/cosmiconfig/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "optional": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", "dev": true, - "requires": { - "for-in": "^1.0.1" + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" } }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "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" + } }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "engines": { + "node": "*" } }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + "node_modules/cz-conventional-changelog": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", + "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "commitizen": "^4.0.3", + "conventional-commit-types": "^3.0.0", + "lodash.map": "^4.5.1", + "longest": "^2.0.1", + "word-wrap": "^1.0.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@commitlint/load": ">6.1.1" + } }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", "dev": true, - "requires": { - "map-cache": "^0.2.2" + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" } }, - "frameguard": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.0.0.tgz", - "integrity": "sha1-e8rUae57lukdEs6zlZx4I1qScuk=" + "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" + } }, - "freemail": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/freemail/-/freemail-1.5.0.tgz", - "integrity": "sha1-k7sPZ8SYcUO0eLQH6Y4ybq2O1OA=", - "requires": { - "tldjs": "^1.5.2" + "node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "fresh": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", - "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=" + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, - "fs-exists-sync": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", - "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "fs-extra": { + "node_modules/default-compare": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" + "dependencies": { + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.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 + "node_modules/default-compare/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "node_modules/default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gaze": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", - "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", + "node_modules/defaults/node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, - "requires": { - "globule": "~0.1.0" + "engines": { + "node": ">=0.8" } }, - "get-own-enumerable-property-symbols": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz", - "integrity": "sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA==", - "dev": true - }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.2", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" } }, - "glob-parent": { + "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "glob-stream": { - "version": "3.1.18", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", - "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", - "dev": true, - "requires": { - "glob": "^4.3.1", - "glob2base": "^0.0.12", - "minimatch": "^2.0.1", - "ordered-read-streams": "^0.1.0", - "through2": "^0.6.1", - "unique-stream": "^1.0.0" - }, - "dependencies": { - "glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", - "dev": true, - "requires": { - "brace-expansion": "^1.0.0" - } - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" } }, - "glob-watcher": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", - "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true, - "requires": { - "gaze": "^0.5.1" + "engines": { + "node": ">=0.10.0" } }, - "glob2base": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true, - "requires": { - "find-index": "^0.1.1" + "engines": { + "node": ">=8" } }, - "global": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", - "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", - "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" + "node_modules/dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==", + "dependencies": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "engines": { + "node": ">=0.8.0" } }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "dev": true, - "requires": { - "ini": "^1.3.4" + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" } }, - "global-modules": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", - "integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=", + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", "dev": true, - "requires": { - "global-prefix": "^0.1.4", - "is-windows": "^0.2.0" + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" } }, - "global-prefix": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", - "integrity": "sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=", + "node_modules/duplexify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, - "requires": { - "homedir-polyfill": "^1.0.0", - "ini": "^1.3.4", - "is-windows": "^0.2.0", - "which": "^1.2.12" + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "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 - }, - "globule": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", - "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", - "dev": true, - "requires": { - "glob": "~3.1.21", - "lodash": "~1.0.1", - "minimatch": "~0.2.11" - }, - "dependencies": { - "glob": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", - "dev": true, - "requires": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" - } - }, - "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, - "inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", - "dev": true - }, - "lodash": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", - "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", - "dev": true - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - } + "node_modules/duplexify/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "node_modules/each-props": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-3.0.0.tgz", + "integrity": "sha512-IYf1hpuWrdzse/s/YJOrFmU15lyhSzxelNVAHTEG3DtP4QsLTWZUzcUL3HMXmKQxXpa4EIrBPpwRgj0aehdvAw==", "dev": true, - "requires": { - "sparkles": "^1.0.0" + "dependencies": { + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "google-auth-library": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-0.10.0.tgz", - "integrity": "sha1-bhW6vuhf0d0U2NEoopW2g41SE24=", - "requires": { - "gtoken": "^1.2.1", - "jws": "^3.1.4", - "lodash.noop": "^3.0.1", - "request": "^2.74.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" } }, - "google-p12-pem": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-0.1.2.tgz", - "integrity": "sha1-M8RqsCGqc0+gMys5YKmj/8svMXc=", - "requires": { - "node-forge": "^0.7.1" - } - }, - "got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "dev": true, - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "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 }, - "gtoken": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-1.2.3.tgz", - "integrity": "sha512-wQAJflfoqSgMWrSBk9Fg86q+sd6s7y6uJhIvvIPz++RElGlMtEqsdAR2oWwZ/WTEtp7P9xFbJRrT976oRgzJ/w==", - "requires": { - "google-p12-pem": "^0.1.0", - "jws": "^3.0.0", - "mime": "^1.4.1", - "request": "^2.72.0" - }, - "dependencies": { - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - } + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" } }, - "gulp": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", - "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", + "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==", "dev": true, - "requires": { - "archy": "^1.0.0", - "chalk": "^1.0.0", - "deprecated": "^0.0.1", - "gulp-util": "^3.0.0", - "interpret": "^1.0.0", - "liftoff": "^2.1.0", - "minimist": "^1.1.0", - "orchestrator": "^0.3.0", - "pretty-hrtime": "^1.0.0", - "semver": "^4.1.0", - "tildify": "^1.0.0", - "v8flags": "^2.0.2", - "vinyl-fs": "^0.3.0" - }, "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", - "dev": true - } + "once": "^1.4.0" } }, - "gulp-eslint": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-4.0.0.tgz", - "integrity": "sha512-+qsePo04v1O3JshpNvww9+bOgZEJ6Cc2/w3mEktfKz0NL0zsh1SWzjyIL2FIM2zzy6IYQYv+j8REZORF8dKX4g==", + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, - "requires": { - "eslint": "^4.0.0", - "gulp-util": "^3.0.8" + "optional": true, + "engines": { + "node": ">=6" } }, - "gulp-nodemon": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/gulp-nodemon/-/gulp-nodemon-2.2.1.tgz", - "integrity": "sha1-2b8Zn1WFRYFZ09KZFT5gtGhotvQ=", - "dev": true, - "requires": { - "colors": "^1.0.3", - "event-stream": "^3.2.1", - "gulp": "^3.9.1", - "nodemon": "^1.10.2" - } - }, - "gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", - "dev": true, - "requires": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, + "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": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true - } + "is-arrayish": "^0.2.1" } }, - "gulplog": { + "node_modules/es-define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "dev": true, - "requires": { - "glogg": "^1.0.0" + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" } }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", "dev": true, - "requires": { - "function-bind": "^1.1.1" + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", "dev": true, - "requires": { - "ansi-regex": "^2.0.0" + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" } }, - "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-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", "dev": true, - "requires": { - "sparkles": "^1.0.0" + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" } }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" } }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "engines": { + "node": ">=6" } }, - "helmet": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.8.1.tgz", - "integrity": "sha512-HzcpQ74kE1gNFvTd8fI/Nz2N0b0Aa/38dSiSVt/ijkwjc50tUp5siXTE9lTBibQ4JlRzp/35Qf+j2bZgHYwg1g==", - "requires": { - "connect": "3.6.2", - "dns-prefetch-control": "0.1.0", - "dont-sniff-mimetype": "1.0.0", - "expect-ct": "0.1.0", - "frameguard": "3.0.0", - "helmet-csp": "2.5.1", - "hide-powered-by": "1.0.0", - "hpkp": "2.0.0", - "hsts": "2.1.0", - "ienoopen": "1.0.0", - "nocache": "2.0.0", - "referrer-policy": "1.1.0", - "x-xss-protection": "1.0.0" - } - }, - "helmet-csp": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.5.1.tgz", - "integrity": "sha512-PLLch8wVcVF2+ViTtSGHIvXqQVjcwGRtBwrNPggC+j28J7eSoPHxbJBr9SvLgh9V3HZa0C1zZFZ6gYVLIrPD0Q==", - "requires": { - "camelize": "1.0.0", - "content-security-policy-builder": "1.1.0", - "dasherize": "2.0.0", - "lodash.reduce": "4.6.0", - "platform": "1.3.4" - } - }, - "hide-powered-by": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.0.0.tgz", - "integrity": "sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys=" - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" - }, - "homedir-polyfill": { + "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "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": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, - "requires": { - "parse-passwd": "^1.0.0" + "engines": { + "node": ">=0.8.0" } }, - "hosted-git-info": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", - "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", - "dev": true - }, - "hpkp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz", - "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI=" - }, - "hsts": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.1.0.tgz", - "integrity": "sha512-zXhh/DqgrTXJ7erTN6Fh5k/xjMhDGXCqdYN3wvxUvGUQvnxcFfUd8E+6vLg/nk3ss1TYMb+DhRl25fYABioTvA==" + "node_modules/eslint": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.7.0.tgz", + "integrity": "sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.7.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "node_modules/eslint-scope": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "husky": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/husky/-/husky-1.0.0-rc.13.tgz", - "integrity": "sha512-ZNNoaBgfOHRA05UHS/etBoWFDu65mjPoohPYQwOqb5155KOovBp8LMkMoNK0kn3VYdsm+HWdtuHbD4XjfzlfpQ==", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.2", - "execa": "^0.9.0", - "find-up": "^3.0.0", - "get-stdin": "^6.0.0", - "is-ci": "^1.1.0", - "pkg-dir": "^3.0.0", - "please-upgrade-node": "^3.1.1", - "read-pkg": "^4.0.1", - "run-node": "^1.0.0", - "slash": "^2.0.0" - }, - "dependencies": { - "execa": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz", - "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "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 - }, - "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": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "read-pkg": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", - "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", - "dev": true, - "requires": { - "normalize-package-data": "^2.3.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0" - } - } + "node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "iconv-lite": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", - "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" + "node_modules/eslint/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" + } }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "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" + } }, - "ienoopen": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ienoopen/-/ienoopen-1.0.0.tgz", - "integrity": "sha1-NGpCj0dKrI9QzzeE6i0PFvYr2ms=" + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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" + } }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true + "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" + } }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "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 }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, - "dependencies": { - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true + "node_modules/eslint/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true - }, - "inquirer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz", - "integrity": "sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=", - "dev": true, - "requires": { - "ansi-escapes": "^1.1.0", - "chalk": "^1.0.0", - "cli-cursor": "^1.0.1", - "cli-width": "^2.0.0", - "external-editor": "^1.1.0", - "figures": "^1.3.5", - "lodash": "^4.3.0", - "mute-stream": "0.0.6", - "pinkie-promise": "^2.0.0", - "run-async": "^2.2.0", - "rx": "^4.1.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.0", - "through": "^2.3.6" + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", - "dev": true - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "ip-regex": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz", - "integrity": "sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0=" - }, - "ipaddr.js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", - "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA=" - }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "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, - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - }, - "dependencies": { - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - } + "engines": { + "node": ">=8" } }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, - "requires": { - "kind-of": "^3.0.2" + "engines": { + "node": ">= 4" } }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "node_modules/eslint/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 }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "requires": { - "binary-extensions": "^1.0.0" + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "requires": { - "ci-info": "^1.5.0" + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, - "requires": { - "kind-of": "^3.0.2" + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "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, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", "dev": true, - "requires": { - "is-primitive": "^2.0.0" + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" } }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, - "requires": { - "number-is-nan": "^1.0.0" + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, - "requires": { - "number-is-nan": "^1.0.0" + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" } }, - "is-function": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", - "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" + "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" + } }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "requires": { - "is-extglob": "^1.0.0" + "engines": { + "node": ">=4.0" } }, - "is-installed-globally": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "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, - "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" + "engines": { + "node": ">=0.10.0" } }, - "is-npm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", - "dev": true + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", "dev": true, - "requires": { - "kind-of": "^3.0.2" + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" } }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "dev": true }, - "is-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", - "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", - "dev": true, - "requires": { - "symbol-observable": "^1.1.0" + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "engines": { + "node": ">=0.4.x" } }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, - "requires": { - "path-is-inside": "^1.0.1" + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/execa/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, - "requires": { - "isobject": "^3.0.1" + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true + "node_modules/exif-parser": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", + "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } }, - "is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "node_modules/express/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", "dev": true, - "requires": { - "is-unc-path": "^1.0.0" + "dependencies": { + "type": "^2.7.2" } }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "dev": true + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "is-unc-path": { + "node_modules/extglob/node_modules/define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, - "requires": { - "unc-path-regex": "^0.1.2" + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } }, - "is-windows": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=", + "node_modules/fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dev": true, + "dependencies": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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 }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true }, - "isemail": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", - "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" + "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 }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", "dev": true, - "requires": { - "isarray": "1.0.0" + "optional": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" } }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } }, - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==", - "dev": true + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "jest-validate": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.6.0.tgz", - "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "leven": "^2.1.0", - "pretty-format": "^23.6.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "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" - } - } + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" } }, - "jimp": { - "version": "0.2.28", - "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.2.28.tgz", - "integrity": "sha1-3VKak3GQ9ClXp5N9Gsw6d2KZbqI=", - "requires": { - "bignumber.js": "^2.1.0", - "bmp-js": "0.0.3", - "es6-promise": "^3.0.2", - "exif-parser": "^0.1.9", - "file-type": "^3.1.0", - "jpeg-js": "^0.2.0", - "load-bmfont": "^1.2.3", - "mime": "^1.3.4", - "mkdirp": "0.5.1", - "pixelmatch": "^4.0.0", - "pngjs": "^3.0.0", - "read-chunk": "^1.0.1", - "request": "^2.65.0", - "stream-to-buffer": "^0.1.0", - "tinycolor2": "^1.1.2", - "url-regex": "^3.0.0" - } - }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" - }, - "joi": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", - "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", - "requires": { - "hoek": "2.x.x", - "isemail": "1.x.x", - "moment": "2.x.x", - "topo": "1.x.x" - } - }, - "jpeg-js": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz", - "integrity": "sha1-U+RI7J0mPmgyZkZ+lELSxaLvVII=" + "node_modules/file-type": { + "version": "16.5.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", + "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", + "dependencies": { + "readable-web-to-node-stream": "^3.0.0", + "strtok3": "^6.2.4", + "token-types": "^4.1.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "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/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } }, - "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==" + "node_modules/find-node-modules": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", + "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", + "dev": true, + "dependencies": { + "findup-sync": "^4.0.0", + "merge": "^2.1.1" + } }, - "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=", + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, - "requires": { - "graceful-fs": "^4.1.6" + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "jsonwebtoken": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.1.tgz", - "integrity": "sha1-fKMk9SFfi+A5zTWmxFu4y3SkSPs=", - "requires": { - "joi": "^6.10.1", - "jws": "^3.1.4", - "lodash.once": "^4.0.0", - "ms": "^2.0.0", - "xtend": "^4.0.1" + "node_modules/find-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" + "node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" } }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" + "node_modules/fined": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-2.0.0.tgz", + "integrity": "sha512-OFRzsL6ZMHz5s0JrsEr+TpdGNCtrVtnuG3x1yzGNiQHT0yaDnXAj8V/lWcpJVrnoDpcwXcASxAZYbuXda2Y82A==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0", + "object.pick": "^1.3.0", + "parse-filepath": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" } }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" + "node_modules/flagged-respawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-2.0.0.tgz", + "integrity": "sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA==", + "dev": true, + "engines": { + "node": ">= 10.13.0" } }, - "kareem": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.0.tgz", - "integrity": "sha512-6hHxsp9e6zQU8nXsP+02HGWXwTkOEw6IROhF2ZA28cYbUk4eJ6QbtZvdqZOdD9YPKghG3apk5eOCvs+tLl3lRg==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, - "requires": { - "is-buffer": "^1.1.5" + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" } }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "dev": true, - "requires": { - "graceful-fs": "^4.1.9" + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" } }, - "latest-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "node_modules/flush-write-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "requires": { - "package-json": "^4.0.0" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "node_modules/flush-write-stream/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==", "dev": true }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "node_modules/flush-write-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "liftoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", - "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", - "dev": true, - "requires": { - "extend": "^3.0.0", - "findup-sync": "^2.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.3", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, + "peerDependenciesMeta": { "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" - } - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "1.0.3" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "1.0.2" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "1.0.2", - "is-windows": "1.0.2", - "resolve-dir": "1.0.1" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "2.0.2", - "homedir-polyfill": "1.0.3", - "ini": "1.3.5", - "is-windows": "1.0.2", - "which": "1.3.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" - } - }, - "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-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "requires": { - "expand-tilde": "2.0.2", - "global-modules": "1.0.0" - } + "optional": true } } }, - "lint-staged": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-7.2.2.tgz", - "integrity": "sha512-BWT3kx242hq5oaKJ8QiazPeHwJnEXImvjmgZfjljMI5HX6RrTxI3cTJXywre6GNafMONCD/suFnEiFmC69Gscg==", + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fork-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", + "integrity": "sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==", + "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/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/freemail": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/freemail/-/freemail-1.7.0.tgz", + "integrity": "sha512-XzEdol9AxxwDN5ISi+J560MgQRKTiGOTRFakRQLUQDEjr48hBMzU5Eo7c2U13zzz3IwcaD+54jWHJrg6/wqRNA==", + "dependencies": { + "tldjs": "^1.5.2" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-mkdirp-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-2.0.1.tgz", + "integrity": "sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.8", + "streamx": "^2.12.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.0.tgz", + "integrity": "sha512-DSrkyMTfAnAm4ks9Go20QGOcXEyW/NmZhvTYBU2rb4afBB393WIMQPWPEDMl/k8xqiNN9HYq2zao3oWXsdl2Tg==", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "dependencies": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gifwrap": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.10.1.tgz", + "integrity": "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==", + "dependencies": { + "image-q": "^4.0.0", + "omggif": "^1.0.10" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-stream": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-8.0.2.tgz", + "integrity": "sha512-R8z6eTB55t3QeZMmU1C+Gv+t5UnNRkA55c5yo67fAVfxODxieTwsjNG7utxS/73NdP1NbDgCrhVEg2h00y4fFw==", + "dev": true, + "dependencies": { + "@gulpjs/to-absolute-glob": "^4.0.0", + "anymatch": "^3.1.3", + "fastq": "^1.13.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "is-negated-glob": "^1.0.0", + "normalize-path": "^3.0.0", + "streamx": "^2.12.5" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-watcher": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-6.0.0.tgz", + "integrity": "sha512-wGM28Ehmcnk2NqRORXFOTOR064L4imSw3EeOqU5bIwUf62eXGwg89WivH6VMahL8zlQHeodzvHpXplrqzrz3Nw==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0", + "chokidar": "^3.5.3" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "optional": true, + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", + "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glogg": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-2.2.0.tgz", + "integrity": "sha512-eWv1ds/zAlz+M1ioHsyKJomfY7jbDDPpwSkv14KQj89bycx1nvK5/2Cj/T9g7kzJcX5Bc7Yv22FjfBZS/jl94A==", + "dev": true, + "dependencies": { + "sparkles": "^2.1.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/google-auth-library": { + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.11.0.tgz", + "integrity": "sha512-epX3ww/mNnhl6tL45EQ/oixsY8JLEgUFoT4A5E/5iAR4esld9Kqv6IJGk7EmGuOgDvaarwF95hU2+v7Irql9lw==", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-auth-library/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/google-auth-library/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/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/gtoken/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/gtoken/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/gulp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-5.0.0.tgz", + "integrity": "sha512-S8Z8066SSileaYw1S2N1I64IUc/myI2bqe2ihOBzO6+nKpvNSg7ZcWJt/AwF8LC/NVN+/QZ560Cb/5OPsyhkhg==", + "dev": true, + "dependencies": { + "glob-watcher": "^6.0.0", + "gulp-cli": "^3.0.0", + "undertaker": "^2.0.0", + "vinyl-fs": "^4.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-cli": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-3.0.0.tgz", + "integrity": "sha512-RtMIitkT8DEMZZygHK2vEuLPqLPAFB4sntSxg4NoDta7ciwGZ18l7JuhCTiS5deOJi2IoK0btE+hs6R4sfj7AA==", + "dev": true, + "dependencies": { + "@gulpjs/messages": "^1.1.0", + "chalk": "^4.1.2", + "copy-props": "^4.0.0", + "gulplog": "^2.2.0", + "interpret": "^3.1.1", + "liftoff": "^5.0.0", + "mute-stdout": "^2.0.0", + "replace-homedir": "^2.0.0", + "semver-greatest-satisfied-range": "^2.0.0", + "string-width": "^4.2.3", + "v8flags": "^4.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-cli/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/gulp-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/gulp-cli/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/gulp-cli/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/gulp-cli/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/gulp-cli/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/gulp-eslint-new": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gulp-eslint-new/-/gulp-eslint-new-2.2.0.tgz", + "integrity": "sha512-B9sBfILAW563MQM81vxWOMeeNbkZTgZEYiwEVmv3fndB5zmGINlA4wbc4qjgPd4kTCtq0sTlFZJV0fpxl8b5kg==", + "dev": true, + "dependencies": { + "@types/eslint": "^8.56.10", + "@types/node": ">=12", + "eslint": "8 || 9", + "fancy-log": "^2.0.0", + "plugin-error": "^2.0.1", + "semver": "^7.6.2", + "ternary-stream": "^3.0.0", + "vinyl-fs": "^4.0.0" + }, + "engines": { + "node": "^12.20 || ^14.13 || >=16" + } + }, + "node_modules/gulp-eslint-new/node_modules/fancy-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-2.0.0.tgz", + "integrity": "sha512-9CzxZbACXMUXW13tS0tI8XsGGmxWzO2DmYrGuBJOJ8k8q2K7hwfJA5qHjuPPe8wtsco33YR9wc+Rlr5wYFvhSA==", + "dev": true, + "dependencies": { + "color-support": "^1.1.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-eslint-new/node_modules/plugin-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-2.0.1.tgz", + "integrity": "sha512-zMakqvIDyY40xHOvzXka0kUvf40nYIuwRE8dWhti2WtjQZ31xAgBZBhxsK7vK3QbRXS1Xms/LO7B5cuAsfB2Gg==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-eslint-new/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gulp-nodemon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/gulp-nodemon/-/gulp-nodemon-2.5.0.tgz", + "integrity": "sha512-vXfaP72xo2C6XOaXrNcLEM3QqDJ1x21S3x97U4YtzN2Rl2kH57++aFkAVxe6BafGRSTxs/xVfE/jNNlCv5Ym2Q==", + "dev": true, + "dependencies": { + "colors": "^1.2.1", + "gulp": "^4.0.0", + "nodemon": "^2.0.2" + } + }, + "node_modules/gulp-nodemon/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/gulp-nodemon/node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", + "dev": true, + "dependencies": { + "async-done": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", + "dev": true, + "dependencies": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/gulp-nodemon/node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/gulp-nodemon/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/gulp-nodemon/node_modules/copy-props": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", + "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", + "dev": true, + "dependencies": { + "each-props": "^1.3.2", + "is-plain-object": "^5.0.0" + } + }, + "node_modules/gulp-nodemon/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "node_modules/gulp-nodemon/node_modules/each-props/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", + "dev": true + }, + "node_modules/gulp-nodemon/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fined/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/gulp-nodemon/node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/gulp-nodemon/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/gulp-nodemon/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "dependencies": { + "sparkles": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/gulp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "dev": true, + "dependencies": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", + "dev": true, + "dependencies": { + "glogg": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "dev": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gulp-nodemon/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-extendable/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", + "dev": true, + "dependencies": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", + "dev": true, + "dependencies": { + "flush-write-stream": "^1.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/gulp-nodemon/node_modules/liftoff/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/micromatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "dependencies": { + "once": "^1.3.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-nodemon/node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", + "dev": true, + "dependencies": { + "value-or-function": "^3.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/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==", + "dev": true + }, + "node_modules/gulp-nodemon/node_modules/semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", + "dev": true, + "dependencies": { + "sver-compat": "^1.5.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-nodemon/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", + "dev": true, + "dependencies": { + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/undertaker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", + "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", + "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", + "dev": true, + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "dependencies": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", + "dev": true, + "dependencies": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl-sourcemap/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "node_modules/gulp-nodemon/node_modules/yargs": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", + "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.1" + } + }, + "node_modules/gulp-nodemon/node_modules/yargs-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", + "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + }, + "node_modules/gulplog": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-2.2.0.tgz", + "integrity": "sha512-V2FaKiOhpR3DRXZuYdRLn/qiY0yI5XmqbTKrYbdemJ+xOh2d2MOweI/XFgMzd/9+1twdvMwllnZbWZNJ+BOm4A==", + "dev": true, + "dependencies": { + "glogg": "^2.2.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/helmet": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", + "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.1.tgz", + "integrity": "sha512-fCqlqLXcBnXa/TJXmT93/A36tJsjdJkibQ1MuIiFyCCYUlpYpIaj2mv1w+3KR6Rzu1IC3slFTje5f6DUp2A2rg==", + "dev": true, + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/image-q": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz", + "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==", + "dependencies": { + "@types/node": "16.9.1" + } + }, + "node_modules/image-q/node_modules/@types/node": { + "version": "16.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", + "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==" + }, + "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/import-fresh/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/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true, + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "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==" + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "optional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/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/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/inquirer/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/inquirer/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/inquirer/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/inquirer/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/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "node_modules/is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, + "node_modules/jimp": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.22.12.tgz", + "integrity": "sha512-R5jZaYDnfkxKJy1dwLpj/7cvyjxiclxU3F4TrI/J4j2rS0niq6YDUMoPn5hs8GDpO+OZGo7Ky057CRtWesyhfg==", + "dependencies": { + "@jimp/custom": "^0.22.12", + "@jimp/plugins": "^0.22.12", + "@jimp/types": "^0.22.12", + "regenerator-runtime": "^0.13.3" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "dev": true, + "optional": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==" + }, + "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, + "optional": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "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==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true, - "requires": { - "chalk": "^2.3.1", - "commander": "^2.14.1", - "cosmiconfig": "^5.0.2", - "debug": "^3.1.0", - "dedent": "^0.7.0", - "execa": "^0.9.0", - "find-parent-dir": "^0.3.0", - "is-glob": "^4.0.0", - "is-windows": "^1.0.2", - "jest-validate": "^23.5.0", - "listr": "^0.14.1", - "lodash": "^4.17.5", - "log-symbols": "^2.2.0", - "micromatch": "^3.1.8", - "npm-which": "^3.0.1", - "p-map": "^1.1.1", - "path-is-inside": "^1.0.2", - "pify": "^3.0.0", - "please-upgrade-node": "^3.0.2", - "staged-git-files": "1.1.1", - "string-argv": "^0.0.2", - "stringify-object": "^3.2.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "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" - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "execa": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz", - "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "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-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, + "optional": true + }, + "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, + "optional": 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/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/just-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", + "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", + "dev": true + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kareem": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", + "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/last-run": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-2.0.0.tgz", + "integrity": "sha512-j+y6WhTLN4Itnf9j5ZQos1BGPCS8DAwmgMroR3OzfxAsBxam0hMw7J8M3KqZl0pLQJ1jNnwIexg5DYpC/ctwEQ==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/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==", + "dev": true + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lead": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-4.0.0.tgz", + "integrity": "sha512-DpMa59o5uGUWWjruMp71e6knmwKU3jRBBn1kjuLWN9EeIOxNeSAwvHf03WIl8g/ZMR2oSQC9ej3yeLBwdDc/pg==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "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/liftoff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-5.0.0.tgz", + "integrity": "sha512-a5BQjbCHnB+cy+gsro8lXJ4kZluzOijzJ1UVVfyJYZC+IP2pLv1h4+aysQeKuTmyO8NAqfyQAk4HWaP/HjcKTg==", + "dev": true, + "dependencies": { + "extend": "^3.0.2", + "findup-sync": "^5.0.0", + "fined": "^2.0.0", + "flagged-respawn": "^2.0.0", + "is-plain-object": "^5.0.0", + "rechoir": "^0.8.0", + "resolve": "^1.20.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/liftoff/node_modules/findup-sync": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", + "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.3", + "micromatch": "^4.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "optional": true + }, + "node_modules/lint-staged": { + "version": "15.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.7.tgz", + "integrity": "sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==", + "dev": true, + "dependencies": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.4", + "execa": "~8.0.1", + "lilconfig": "~3.1.1", + "listr2": "~8.2.1", + "micromatch": "~4.0.7", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.4.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { "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" - } + "optional": true } } }, - "listr": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", - "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", - "dev": true, - "requires": { - "@samverschueren/stream-to-observable": "^0.3.0", - "is-observable": "^1.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.5.0", - "listr-verbose-renderer": "^0.5.0", - "p-map": "^2.0.0", - "rxjs": "^6.3.3" - }, - "dependencies": { - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - } + "node_modules/listr2": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.3.tgz", + "integrity": "sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/load-bmfont": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.2.tgz", + "integrity": "sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==", + "dependencies": { + "buffer-equal": "0.0.1", + "mime": "^1.3.4", + "parse-bmfont-ascii": "^1.0.3", + "parse-bmfont-binary": "^1.0.5", + "parse-bmfont-xml": "^1.1.4", + "phin": "^3.7.1", + "xhr": "^2.0.1", + "xtend": "^4.0.0" + } + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true, + "optional": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "optional": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/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/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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" } }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", - "dev": true - }, - "listr-update-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", - "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^2.3.0", - "strip-ansi": "^3.0.1" - }, + "node_modules/log-symbols/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": { - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "^1.0.0" - } - } + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "listr-verbose-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", - "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "node_modules/log-symbols/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/log-symbols/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, - "requires": { - "chalk": "^2.4.1", - "cli-cursor": "^2.1.0", - "date-fns": "^1.27.2", - "figures": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "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" - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "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" - } - } + "engines": { + "node": ">=8" } }, - "load-bmfont": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.0.tgz", - "integrity": "sha512-kT63aTAlNhZARowaNYcY29Fn/QYkc52M3l6V1ifRcPewg2lvUZDAj7R6dXjOL9D0sict76op3T5+odumDSF81g==", - "requires": { - "buffer-equal": "0.0.1", - "mime": "^1.3.4", - "parse-bmfont-ascii": "^1.0.3", - "parse-bmfont-binary": "^1.0.5", - "parse-bmfont-xml": "^1.1.4", - "phin": "^2.9.1", - "xhr": "^2.0.1", - "xtend": "^4.0.0" + "node_modules/log-symbols/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" } }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "node_modules/log-update": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", + "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" + "dependencies": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "engines": { + "node": ">=14.16" }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true + "node_modules/log-update/node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", "dev": true }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true + "node_modules/log-update/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true + "node_modules/log-update/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true + "node_modules/log-update/node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "node_modules/log-update/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", "dev": true, - "requires": { - "lodash._root": "^3.0.0" + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "node_modules/longest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", + "integrity": "sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==", "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" + "engines": { + "node": ">=0.10.0" } }, - "lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", - "dev": true + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } }, - "lodash.noop": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-3.0.1.tgz", - "integrity": "sha1-OBiPTWUKOkdCWEObluxFsyYXEzw=" + "node_modules/make-iterator/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "lodash.reduce": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", - "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true + "node_modules/matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", + "dev": true, + "dependencies": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "engines": { + "node": ">= 0.10.0" + } }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "node_modules/matchdep/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "node_modules/matchdep/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, - "requires": { - "chalk": "^2.0.1" + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "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" - } - } + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "log-update": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", - "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "node_modules/matchdep/node_modules/findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "cli-cursor": "^2.0.0", - "wrap-ansi": "^3.0.1" + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/matchdep/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - } + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "longest": { + "node_modules/matchdep/node_modules/is-extendable": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true + "node_modules/matchdep/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "node_modules/matchdep/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "node_modules/matchdep/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, - "requires": { - "pify": "^3.0.0" + "dependencies": { + "is-buffer": "^1.1.5" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "node_modules/matchdep/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, - "requires": { - "kind-of": "^6.0.2" + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "node_modules/matchdep/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, - "requires": { - "object-visit": "^1.0.0" + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "math-random": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", - "dev": true - }, - "md5": { + "node_modules/md5": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", - "requires": { + "dependencies": { "charenc": "~0.0.1", "crypt": "~0.0.1", "is-buffer": "~1.1.1" } }, - "media-typer": { + "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } }, - "memory-pager": { + "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" }, - "merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", + "node_modules/merge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", "dev": true }, - "merge-descriptors": { + "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, - "methods": { + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", - "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" - }, - "mime-db": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", - "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" - }, - "mime-types": { - "version": "2.1.25", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", - "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", - "requires": { - "mime-db": "1.42.0" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } }, - "min-document": { + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "requires": { + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dependencies": { "dom-walk": "^0.1.0" } }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "requires": { + "dependencies": { "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "mixin-deep": { + "node_modules/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, - "requires": { + "dependencies": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" } }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" } }, - "moment": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", - "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" + "node_modules/moment-timezone": { + "version": "0.5.45", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz", + "integrity": "sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } }, - "moment-timezone": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.21.tgz", - "integrity": "sha512-j96bAh4otsgj3lKydm3K7kdtA3iKf2m6MY2iSYCzCm5a1zmHo1g+aK3068dDEeocLZQIS9kU8bsdQHLqEvgW0A==", - "requires": { - "moment": ">= 2.9.0" + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" } }, - "mongodb": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.6.tgz", - "integrity": "sha512-E5QJuXQoMlT7KyCYqNNMfAkhfQD79AT4F8Xd+6x37OX+8BL17GyXyWvfm6wuyx4wnzCCPoCSLeMeUN2S7dU9yw==", - "requires": { - "mongodb-core": "3.1.5", - "safe-buffer": "^5.1.2" + "node_modules/mongodb-connection-string-url/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" } }, - "mongodb-core": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.5.tgz", - "integrity": "sha512-emT/tM4ZBinqd6RZok+EzDdtN4LjYJIckv71qQVOEFmvXgT5cperZegVmTgox/1cx4XQu6LJ5ZuIwipP/eKdQg==", - "requires": { - "bson": "^1.1.0", - "require_optional": "^1.0.1", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" + "node_modules/mongodb-connection-string-url/node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dependencies": { + "punycode": "^2.3.0" }, + "engines": { + "node": ">=14" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", "dependencies": { - "bson": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.3.tgz", - "integrity": "sha512-TdiJxMVnodVS7r0BdL42y/pqC9cL2iKynVwA0Ho3qbsQYr428veL3l7BQyuqiw+Q5SqqoT0m4srSY/BlZ9AxXg==" - } + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" } }, - "mongodb-uri": { + "node_modules/mongodb-uri": { "version": "0.9.7", "resolved": "https://registry.npmjs.org/mongodb-uri/-/mongodb-uri-0.9.7.tgz", - "integrity": "sha1-D3ca0W9IOuZfQoeWlCjp+8SqYYE=" + "integrity": "sha1-D3ca0W9IOuZfQoeWlCjp+8SqYYE=", + "engines": { + "node": ">= 0.6.0" + } }, - "mongoose": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.3.2.tgz", - "integrity": "sha512-07fpCMqvCiSdKXIygt3aAeNFJYjQPjDXILbwBEmF0e8gy2hSKMNuP5QG4J6L8m9BhjVxcvoLiPzaGKN7I/7lLg==", - "requires": { - "async": "2.6.1", - "bson": "~1.0.5", - "kareem": "2.3.0", - "lodash.get": "4.4.2", - "mongodb": "3.1.6", - "mongodb-core": "3.1.5", - "mongoose-legacy-pluralize": "1.0.2", - "mpath": "0.5.1", - "mquery": "3.2.0", - "ms": "2.0.0", - "regexp-clone": "0.0.1", - "safe-buffer": "5.1.2", - "sliced": "1.0.1" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "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/mongoose": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.1.tgz", + "integrity": "sha512-OhVcwVl91A1G6+XpjDcpkGP7l7ikZkxa0DylX7NT/lcEqAjggzSdqDxb48A+xsDxqNAr0ntSJ1yiE3+KJTOd5Q==", + "dependencies": { + "bson": "^6.7.0", + "kareem": "2.6.3", + "mongodb": "6.7.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "17.1.3" + }, + "engines": { + "node": ">=16.20.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" } }, - "mongoose-legacy-pluralize": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", - "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" - }, - "morgan": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.8.2.tgz", - "integrity": "sha1-eErHc05KRTqcbm6GgKkyknXItoc=", - "requires": { - "basic-auth": "~1.1.0", - "debug": "2.6.8", - "depd": "~1.1.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.1" + "node_modules/mongoose/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==", + "optional": true, + "peer": true, + "dependencies": { + "debug": "4" }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/mongoose/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "optional": true, + "peer": true, "dependencies": { - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "mpath": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.5.1.tgz", - "integrity": "sha512-H8OVQ+QEz82sch4wbODFOz+3YQ61FYz/z3eJ5pIdbMEaUzDqA268Wd+Vt4Paw9TJfvDgVKaayC0gBzMIw2jhsg==" + "node_modules/mongoose/node_modules/debug/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==", + "optional": true, + "peer": true }, - "mquery": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.0.tgz", - "integrity": "sha512-qPJcdK/yqcbQiKoemAt62Y0BAc0fTEKo1IThodBD+O5meQRJT/2HSe5QpBNwaa4CjskoGrYWsEyjkqgiE0qjhg==", - "requires": { - "bluebird": "3.5.1", - "debug": "3.1.0", - "regexp-clone": "0.0.1", - "safe-buffer": "5.1.2", - "sliced": "1.0.1" + "node_modules/mongoose/node_modules/gaxios": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", + "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", + "optional": true, + "peer": true, + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongoose/node_modules/gcp-metadata": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", + "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", + "optional": true, + "peer": true, "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } + "gaxios": "^5.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongoose/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "peer": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mongoose/node_modules/mongodb": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.7.0.tgz", + "integrity": "sha512-TMKyHdtMcO0fYBNORiYdmM25ijsHs+Njs963r4Tro4OQZzqYigAzYQouwWRg4OIaiLRUEGUh/1UAcH5lxdSLIA==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true }, - "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==" + "socks": { + "optional": true + } + } + }, + "node_modules/mongoose/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/mquery/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "ms": { + "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==" }, - "multer": { + "node_modules/multer": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/multer/-/multer-1.3.0.tgz", - "integrity": "sha1-CSsmcPaEb6SRSWXvyM+Uwg/sbNI=", - "requires": { + "integrity": "sha512-wbAkTsh0QXkvqvHCU2qSLEXLuRN7IKMEe80+JrXfJzANniPNgrNcDOMKfGgR1EhL7y7MHIbODVwT7uaVY20ggw==", + "deprecated": "Multer 1.x is affected by CVE-2022-24434. This is fixed in v1.4.4-lts.1 which drops support for versions of Node.js before 6. Please upgrade to at least Node.js 6 and version 1.4.4-lts.1 of Multer. If you need support for older versions of Node.js, we are open to accepting patches that would fix the CVE on the main 1.x release line, whilst maintaining compatibility with Node.js 0.10.", + "dependencies": { "append-field": "^0.1.0", "busboy": "^0.2.11", "concat-stream": "^1.5.0", @@ -6534,42 +7829,46 @@ "type-is": "^1.6.4", "xtend": "^4.0.0" }, - "dependencies": { - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" - } + "engines": { + "node": ">= 0.10.0" } }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "node_modules/multer/node_modules/object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mute-stdout": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-2.0.0.tgz", + "integrity": "sha512-32GSKM3Wyc8dg/p39lWPKYu8zci9mJFzV1Np9Of0ZEpe6Fhssn/FbI7ywAMd40uX+p3ZKh3T5EeCFv81qS3HmQ==", "dev": true, - "requires": { - "duplexer2": "0.0.2" + "engines": { + "node": ">= 10.13.0" } }, - "mute-stream": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz", - "integrity": "sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=", + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "node_modules/nan": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", + "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", "dev": true, "optional": true }, - "nanomatch": { + "node_modules/nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, - "requires": { + "dependencies": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "define-property": "^2.0.2", @@ -6582,1904 +7881,1872 @@ "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "natives": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", - "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", - "dev": true + "node_modules/nanomatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/nanomatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "natural-compare": { + "node_modules/nanomatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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 }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } }, - "nocache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.0.0.tgz", - "integrity": "sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA=" + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true }, - "node-fetch": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", - "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=", - "dev": true, - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node-forge": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz", - "integrity": "sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==" - }, - "nodemailer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.0.1.tgz", - "integrity": "sha1-uVhksH+s7oKH6CMu/9bx1W7HWrI=" + "node_modules/nodemailer": { + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz", + "integrity": "sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==", + "engines": { + "node": ">=6.0.0" + } }, - "nodemon": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz", - "integrity": "sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==", + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, - "requires": { - "chokidar": "^2.1.8", - "debug": "^3.2.6", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", - "undefsafe": "^2.0.2", - "update-notifier": "^2.5.0" + "undefsafe": "^2.0.5" }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" } }, - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "requires": { - "abbrev": "1" + "dependencies": { + "ms": "^2.1.1" } }, - "normalize-package-data": { + "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, - "requires": { + "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" + "engines": { + "node": ">=0.10.0" } }, - "now": { + "node_modules/now": { "version": "11.4.6", "resolved": "https://registry.npmjs.org/now/-/now-11.4.6.tgz", - "integrity": "sha512-5SMS8lVuCzqD55CPQlGcjvOJJJPuDSLoqKIIGR4uEooCbDhHl//dHZmBpT1uLSwT1MYvhYUMf9OpFQRwXG4KEg==" + "integrity": "sha512-5SMS8lVuCzqD55CPQlGcjvOJJJPuDSLoqKIIGR4uEooCbDhHl//dHZmBpT1uLSwT1MYvhYUMf9OpFQRwXG4KEg==", + "deprecated": "\"now\" is deprecated and will stop receiving updates on December 31, 2020. Please use \"vercel\" instead.", + "hasInstallScript": true, + "bin": { + "now": "download/dist/now" + } }, - "npm-path": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", - "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", + "node_modules/now-and-later": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-3.0.0.tgz", + "integrity": "sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg==", "dev": true, - "requires": { - "which": "^1.2.10" + "dependencies": { + "once": "^1.4.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, - "requires": { - "path-key": "^2.0.0" + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "npm-which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", - "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, - "requires": { - "commander": "^2.9.0", - "npm-path": "^2.0.2", - "which": "^1.2.10" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "number-is-nan": { + "node_modules/number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "object-assign": { + "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } }, - "object-copy": { + "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, - "requires": { + "dependencies": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", "kind-of": "^3.0.3" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, + "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" } }, - "object-visit": { + "node_modules/object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dev": true, - "requires": { + "dependencies": { "isobject": "^3.0.0" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "object.defaults": { + "node_modules/object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", "dev": true, - "requires": { + "dependencies": { "array-each": "^1.0.1", "array-slice": "^1.0.0", "for-own": "^1.0.0", "isobject": "^3.0.0" }, - "dependencies": { - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "engines": { + "node": ">=0.10.0" } }, - "object.map": { + "node_modules/object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", "dev": true, - "requires": { + "dependencies": { "for-own": "^1.0.0", "make-iterator": "^1.0.0" }, - "dependencies": { - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - } - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" + "engines": { + "node": ">=0.10.0" } }, - "object.pick": { + "node_modules/object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dev": true, - "requires": { + "dependencies": { "isobject": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", + "dev": true, "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "on-finished": { + "node_modules/omggif": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz", + "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==" + }, + "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { + "dependencies": { "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" } }, - "on-headers": { + "node_modules/on-headers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } }, - "once": { + "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, - "requires": { + "dependencies": { "wrappy": "1" } }, - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, - "opencollective": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz", - "integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=", - "dev": true, - "requires": { - "babel-polyfill": "6.23.0", - "chalk": "1.1.3", - "inquirer": "3.0.6", - "minimist": "1.2.0", - "node-fetch": "1.6.3", - "opn": "4.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "inquirer": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz", - "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=", - "dev": true, - "requires": { - "ansi-escapes": "^1.1.0", - "chalk": "^1.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.1", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx": "^4.1.0", - "string-width": "^2.0.0", - "strip-ansi": "^3.0.0", - "through": "^2.3.6" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - } + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "opn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", - "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, - "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" + "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.5" + }, + "engines": { + "node": ">= 0.8.0" } }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "orchestrator": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", - "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", + "node_modules/ora/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, - "requires": { - "end-of-stream": "~0.1.5", - "sequencify": "~0.0.7", - "stream-consume": "~0.1.0" + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "ordered-read-streams": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", - "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", - "dev": true + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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" + } }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true + "node_modules/ora/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" + } }, - "os-shim": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "node_modules/ora/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 }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true + "node_modules/ora/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" + } }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "node_modules/ora/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" + } }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "node_modules/ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", "dev": true, - "requires": { - "p-try": "^1.0.0" + "dependencies": { + "readable-stream": "^2.0.1" } }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "node_modules/ordered-read-streams/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "requires": { - "p-limit": "^1.1.0" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "node_modules/ordered-read-streams/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==", "dev": true }, - "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 + "node_modules/ordered-read-streams/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } }, - "package-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", "dev": true, - "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "pad-right": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", - "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=", + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "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, - "requires": { - "repeat-string": "^1.5.2" + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "parse-bmfont-ascii": { + "node_modules/parse-bmfont-ascii": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", - "integrity": "sha1-Eaw8P/WPfCAgqyJ2kHkQjU36AoU=" + "integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==" }, - "parse-bmfont-binary": { + "node_modules/parse-bmfont-binary": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz", - "integrity": "sha1-0Di0dtPp3Z2x4RoLDlOiJ5K2kAY=" + "integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==" }, - "parse-bmfont-xml": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz", - "integrity": "sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==", - "requires": { + "node_modules/parse-bmfont-xml": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz", + "integrity": "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==", + "dependencies": { "xml-parse-from-string": "^1.0.0", - "xml2js": "^0.4.5" + "xml2js": "^0.5.0" + } + }, + "node_modules/parse-bmfont-xml/node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" } }, - "parse-filepath": { + "node_modules/parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, - "requires": { + "dependencies": { "is-absolute": "^1.0.0", "map-cache": "^0.2.0", "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" } }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - } - }, - "parse-headers": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz", - "integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==" + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" }, - "parse-json": { + "node_modules/parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", "dev": true, - "requires": { + "dependencies": { "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "parse-node-version": { + "node_modules/parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.10" + } }, - "parse-passwd": { + "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "parseurl": { + "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } }, - "pascalcase": { + "node_modules/pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "path-dirname": { + "node_modules/path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", "dev": true }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" + "engines": { + "node": ">=8" } }, - "path-is-absolute": { + "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 - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true + "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" + } }, - "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==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "path-root": { + "node_modules/path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, - "requires": { + "dependencies": { "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "path-root-regex": { + "node_modules/path-root-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", - "dev": true + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "path-to-regexp": { + "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", "dev": true, - "requires": { - "pify": "^2.0.0" + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "dev": true, - "requires": { - "through": "~2.3" + "node_modules/peek-readable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", + "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "node_modules/phin": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", + "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", + "dependencies": { + "centra": "^2.7.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "optional": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "phin": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz", - "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==" + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } }, - "pify": { + "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "pinkie": { + "node_modules/pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "pinkie-promise": { + "node_modules/pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, - "requires": { + "dependencies": { "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "pixelmatch": { + "node_modules/pixelmatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", - "integrity": "sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ=", - "requires": { + "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", + "dependencies": { "pngjs": "^3.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" } }, - "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" - } - }, - "platform": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.4.tgz", - "integrity": "sha1-bw+xftqqSPIUQrOpdcBjEw8cPr0=" - }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "requires": { - "semver-compare": "^1.0.0" - } - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true - }, - "pngjs": { + "node_modules/pixelmatch/node_modules/pngjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "engines": { + "node": ">=4.0.0" + } }, - "posix-character-classes": { + "node_modules/pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "engines": { + "node": ">= 0.4" + } }, - "prettier": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.2.tgz", - "integrity": "sha512-McHPg0n1pIke+A/4VcaS2en+pTNjy4xF+Uuq86u/5dyDO59/TtFZtQ708QIRkEZ3qwKz3GVkVa6mpxK/CpB8Rg==", - "dev": true + "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" + } }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" + "bin": { + "prettier": "bin/prettier.cjs" }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "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" - } - } + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "pretty-hrtime": { + "node_modules/pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", - "dev": true + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "dev": true, + "engines": { + "node": ">= 0.8" + } }, - "process": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", - "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } }, - "process-nextick-args": { + "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, - "proxy-addr": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", - "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=", - "requires": { - "forwarded": "~0.1.0", - "ipaddr.js": "1.4.0" + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } }, - "psl": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.5.0.tgz", - "integrity": "sha512-4vqUjKi2huMu1OJiLhi3jN6jeeKvMZdI1tYgi/njW5zV52jNLgSAZSdN16m9bJFe61/cT8ulmw4qFitV9QRsEA==" + "node_modules/pumpify/node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/pumpify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } }, - "pstree.remy": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", - "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", + "node_modules/pumpify/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==", "dev": true }, - "punycode": { + "node_modules/pumpify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "querystring": { + "node_modules/querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } }, - "randomatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + { + "type": "consulting", + "url": "https://feross.org/support" } - } + ] + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, + "node_modules/randombytes": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz", + "integrity": "sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg==" }, - "randomstring": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.1.5.tgz", - "integrity": "sha1-bfBij3XL1ZMpMNn+OrTpVqGFGMM=", - "requires": { - "array-uniq": "1.0.2" + "node_modules/randomstring": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.3.0.tgz", + "integrity": "sha512-gY7aQ4i1BgwZ8I1Op4YseITAyiDiajeZOPQUbIq9TPGPhUm5FX59izIaOpmKbME1nmnEiABf28d9K2VSii6BBg==", + "dependencies": { + "randombytes": "2.0.3" + }, + "bin": { + "randomstring": "bin/randomstring" + }, + "engines": { + "node": "*" } }, - "range-parser": { + "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } }, - "raven": { + "node_modules/raven": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/raven/-/raven-2.6.0.tgz", "integrity": "sha1-OAaoLJ7ozT51w7fqe7GTWq0JLQw=", - "requires": { + "deprecated": "Please upgrade to @sentry/node. See the migration guide https://bit.ly/3ybOlo7", + "dependencies": { "cookie": "0.3.1", "md5": "^2.2.1", "stack-trace": "0.0.10", "timed-out": "4.0.1", "uuid": "3.0.0" }, - "dependencies": { - "uuid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz", - "integrity": "sha1-Zyj8BFnEUNeWqZwxg3VpvfZy1yg=" - } + "bin": { + "raven": "bin/raven" + }, + "engines": { + "node": ">= 4.0.0" } }, - "raw-body": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz", - "integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=", - "requires": { - "bytes": "2.4.0", - "iconv-lite": "0.4.15", - "unpipe": "1.0.0" + "node_modules/raven/node_modules/uuid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz", + "integrity": "sha1-Zyj8BFnEUNeWqZwxg3VpvfZy1yg=", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" } }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "read-chunk": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-1.0.1.tgz", - "integrity": "sha1-X2jKswfmY/GZk1J9m1icrORmEZQ=" - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, - "requires": { - "load-json-file": "^2.0.0", + "dependencies": { + "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "readable-stream": { + "node_modules/readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { + "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" - }, + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - } + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "node_modules/readable-web-to-node-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "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" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "safe-buffer": "~5.2.0" } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "requires": { - "resolve": "^1.1.6" + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, - "referrer-policy": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.1.0.tgz", - "integrity": "sha1-NXdOtzW/UPtsB46DM0tHI1AgfXk=" - }, - "regenerator-runtime": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", - "dev": true - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "regex-not": { + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, - "requires": { + "dependencies": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "regexp-clone": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz", - "integrity": "sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk=" + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", - "dev": true + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } }, - "registry-auth-token": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "node_modules/regex-not/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, - "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "node_modules/remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", "dev": true, - "requires": { - "rc": "^1.0.1" + "dependencies": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" } }, - "remove-trailing-separator": { + "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=", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", "dev": true }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "repeat-string": { + "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "engines": { + "node": ">=0.10" + } }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", "dev": true, - "requires": { - "is-finite": "^1.0.0" + "engines": { + "node": ">= 10" } }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true + "node_modules/replace-homedir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-2.0.0.tgz", + "integrity": "sha512-bgEuQQ/BHW0XkkJtawzrfzHFSN70f/3cNOiHa2QsYxqrjaC30X1k74FJ6xswVBP0sr0SpGIdVFuPwfrYziVeyw==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" - } + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "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, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "dev": true - } + "optional": true, + "engines": { + "node": ">=0.10.0" } }, - "require_optional": { + "node_modules/require-main-filename": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", - "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", - "requires": { - "resolve-from": "^2.0.0", - "semver": "^5.1.0" + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "resolve": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", - "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, - "requires": { - "path-parse": "^1.0.6" + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "resolve-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", - "integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=", + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "requires": { - "expand-tilde": "^1.2.2", - "global-modules": "^0.2.3" + "optional": true, + "engines": { + "node": ">=8" } }, - "resolve-from": { + "node_modules/resolve-options": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-2.0.0.tgz", + "integrity": "sha512-/FopbmmFOQCfsCx77BRFdKOniglTiHumLgwvd6IDPihy1GKkadZbgQJBcTb2lMzSR1pndzd96b1nZrreZ7+9/A==", + "dev": true, + "dependencies": { + "value-or-function": "^4.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } }, - "resolve-url": { + "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", "dev": true }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "ret": { + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "right-pad": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz", - "integrity": "sha1-jKCMLLtbVedNr6lr9/0aJ9VoyNA=", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "dev": true, + "engines": { + "node": ">=0.12" } }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, - "requires": { - "is-promise": "^2.1.0" + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "run-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", - "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", - "dev": true - }, - "rx": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", - "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, - "requires": { - "rx-lite": "*" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" } }, - "rxjs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", - "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "requires": { - "tslib": "^1.9.0" + "dependencies": { + "tslib": "^2.1.0" } }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "safe-regex": { + "node_modules/safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, - "requires": { + "dependencies": { "ret": "~0.1.10" } }, - "safer-buffer": { + "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" - } - }, - "sax": { + "node_modules/sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true + "node_modules/semver-greatest-satisfied-range": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-2.0.0.tgz", + "integrity": "sha512-lH3f6kMbwyANB7HuOWRMlLCa2itaCrZJ+SAqqkSZrZKO/cAsk2EOyaKHUtNkVLFyFW9pct22SFesFp3Z7zpA0g==", + "dev": true, + "dependencies": { + "sver": "^1.8.3" + }, + "engines": { + "node": ">= 10.13.0" + } }, - "semver-diff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", - "dev": true, - "requires": { - "semver": "^5.0.3" - } - }, - "send": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/send/-/send-0.15.3.tgz", - "integrity": "sha1-UBP5+ZAj31DRvZiSwZ4979HVMwk=", - "requires": { - "debug": "2.6.7", - "depd": "~1.1.0", - "destroy": "~1.0.4", - "encodeurl": "~1.0.1", + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "etag": "~1.8.0", - "fresh": "0.5.0", - "http-errors": "~1.6.1", - "mime": "1.3.4", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.3.1" + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "sequencify": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", - "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, - "serve-static": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.3.tgz", - "integrity": "sha1-n0uhni8wMMVH+K+ZEHg47DjVseI=", - "requires": { - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "parseurl": "~1.3.1", - "send": "0.15.3" + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "set-value": { + "node_modules/set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, - "requires": { + "dependencies": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", "is-plain-object": "^2.0.3", "split-string": "^3.0.1" }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "engines": { + "node": ">=0.10.0" } }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + "node_modules/set-value/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "shebang-command": { + "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "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, - "requires": { - "shebang-regex": "^1.0.0" + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shelljs": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.6.tgz", - "integrity": "sha1-N5zM+1a5HIYB5HkzVutTgpJN6a0=", + "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, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" + "engines": { + "node": ">=8" } }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true + "node_modules/sift": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==" }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0" + "dependencies": { + "semver": "~7.0.0" }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "sliced": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "snapdragon": { + "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, - "requires": { + "dependencies": { "base": "^0.11.1", "debug": "^2.2.0", "define-property": "^0.2.5", @@ -8489,1269 +9756,1558 @@ "source-map-resolve": "^0.5.0", "use": "^3.1.0" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "engines": { + "node": ">=0.10.0" } }, - "snapdragon-node": { + "node_modules/snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, - "requires": { + "dependencies": { "define-property": "^1.0.0", "isobject": "^3.0.0", "snapdragon-util": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "snapdragon-util": { + "node_modules/snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, - "requires": { + "dependencies": { "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "source-map": { + "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 + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", "dev": true, - "requires": { - "atob": "^2.1.1", + "dependencies": { + "atob": "^2.1.2", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", "urix": "^0.1.0" } }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", "dev": true }, - "sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", - "dev": true + "node_modules/sparkles": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-2.1.0.tgz", + "integrity": "sha512-r7iW1bDw8R/cFifrD3JnQJX0K1jqT0kprL48BiBpLZLJPmAm34zsVBsK5lc7HirZYZqMW65dOXZgbAGt/I6frg==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } }, - "sparse-bitfield": { + "node_modules/sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "optional": true, - "requires": { + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { "memory-pager": "^1.0.2" } }, - "spawn-sync": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "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.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "dev": true + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "engines": { + "node": "*" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-composer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-composer/-/stream-composer-1.0.2.tgz", + "integrity": "sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w==", + "dev": true, + "dependencies": { + "streamx": "^2.13.2" + } + }, + "node_modules/stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "dev": true + }, + "node_modules/streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/streamx": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", + "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", "dev": true, - "requires": { - "concat-stream": "^1.4.7", - "os-shim": "^0.1.2" + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" } }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "engines": { + "node": ">=0.6.19" } }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } }, - "spdx-expression-parse": { + "node_modules/string-width/node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "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, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "engines": { + "node": ">=8" } }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "speakingurl": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.0.tgz", - "integrity": "sha512-70UD8Mm2cMkufkiUJ6tt7DLdLytYxTc1OwzXYJ9LVutfIoNx/Dmuj6vj/x0qAbUEFdyYKaHza1K/B1sI4hEk1A==" - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "requires": { - "through": "2" + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", "dev": true, - "requires": { - "extend-shallow": "^3.0.0" + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" - }, - "staged-git-files": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.1.tgz", - "integrity": "sha512-H89UNKr1rQJvI1c/PIR3kiAMBV23yvR7LItZiV74HWZwzt7f3YHuujJ9nJZlt58WlFox7XQsOahexwk7nTe69A==", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "engines": { + "node": ">=12" }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", + "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, - "requires": { - "duplexer": "~0.1.1", - "through": "~2.3.4" + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "stream-consume": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", - "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", - "dev": true - }, - "stream-to": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-to/-/stream-to-0.2.2.tgz", - "integrity": "sha1-hDBgmNhf25kLn6MAsbPM9V6O8B0=" - }, - "stream-to-buffer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stream-to-buffer/-/stream-to-buffer-0.1.0.tgz", - "integrity": "sha1-JnmdkDqyAlyb1VCsRxcbAPjdgKk=", - "requires": { - "stream-to": "~0.2.0" + "node_modules/strtok3": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", + "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^4.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + "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" + } }, - "string-argv": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", - "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", - "dev": true + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "node_modules/sver": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/sver/-/sver-1.8.4.tgz", + "integrity": "sha512-71o1zfzyawLfIWBOmw8brleKyvnbn73oVHNCsu51uPMz/HWiKkkXsI31JjHW5zqXEqnPYkIiHd8ZmL7FCimLEA==", "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "optionalDependencies": { + "semver": "^6.3.0" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "node_modules/sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", + "dev": true, + "dependencies": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "node_modules/sver/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" + "optional": true, + "bin": { + "semver": "bin/semver.js" } }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", "dev": true, - "requires": { - "ansi-regex": "^2.0.0" + "dependencies": { + "streamx": "^2.12.5" } }, - "strip-bom": { + "node_modules/ternary-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true + "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-3.0.0.tgz", + "integrity": "sha512-oIzdi+UL/JdktkT+7KU5tSIQjj8pbShj3OASuvDEhm0NT5lppsm7aXWAmAq4/QMaBIyfuEcNLbAQA+HpaISobQ==", + "dev": true, + "dependencies": { + "duplexify": "^4.1.1", + "fork-stream": "^0.0.4", + "merge-stream": "^2.0.0", + "through2": "^3.0.1" + } }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "node_modules/ternary-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true + "node_modules/ternary-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "dev": true, - "requires": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "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" - } - }, - "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" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "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" - } - } + "node_modules/ternary-stream/node_modules/through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" } }, - "term-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "node_modules/text-decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", + "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", "dev": true, - "requires": { - "execa": "^0.7.0" + "dependencies": { + "b4a": "^1.6.4" } }, - "text-table": { + "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 }, - "through": { + "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, - "through2": { + "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, - "requires": { + "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" - }, + } + }, + "node_modules/through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dev": true, "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "through2": "~2.0.0", + "xtend": "~4.0.0" } }, - "tildify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/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==", + "dev": true + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "requires": { - "os-homedir": "^1.0.0" + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "time-stamp": { + "node_modules/time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", - "dev": true + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "timed-out": { + "node_modules/timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "engines": { + "node": ">=0.10.0" + } }, - "tinycolor2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", - "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" + "node_modules/timm": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz", + "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==" + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" }, - "tldjs": { + "node_modules/tldjs": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/tldjs/-/tldjs-1.8.0.tgz", "integrity": "sha1-ucFr1t41e1X/y+fVvkH2s8p24/o=", - "requires": { + "hasInstallScript": true, + "dependencies": { "punycode": "^1.4.1" }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/tldjs/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" } }, - "tmp": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz", - "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=", + "node_modules/to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", "dev": true, - "requires": { - "os-tmpdir": "~1.0.1" + "dependencies": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "to-object-path": { + "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dev": true, - "requires": { + "dependencies": { "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "to-regex": { + "node_modules/to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, - "requires": { + "dependencies": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "dependencies": { + "is-number": "^7.0.0" }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-regex/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - } + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "topo": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", - "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", - "requires": { - "hoek": "2.x.x" + "node_modules/to-regex/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "node_modules/to-regex/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, - "requires": { - "nopt": "~1.0.10" + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "node_modules/to-regex/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-through": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-3.0.0.tgz", + "integrity": "sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw==", + "dev": true, + "dependencies": { + "streamx": "^2.12.5" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/token-types": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", + "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/token-types/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "bin": { + "nodetouch": "bin/nodetouch.js" } }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", "dev": true }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" + "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" } }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "type-is": { + "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { + "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" } }, - "typedarray": { + "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, - "unc-path-regex": { + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, - "undefsafe": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", - "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", + "node_modules/undertaker": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-2.0.0.tgz", + "integrity": "sha512-tO/bf30wBbTsJ7go80j0RzA2rcwX6o7XPBpeFcb+jzoeb4pfMM2zUeSDIkY1AWqeZabWxaQZ/h8N9t35QKDLPQ==", "dev": true, - "requires": { - "debug": "^2.2.0" + "dependencies": { + "bach": "^2.0.1", + "fast-levenshtein": "^3.0.0", + "last-run": "^2.0.0", + "undertaker-registry": "^2.0.0" }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/undertaker-registry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-2.0.0.tgz", + "integrity": "sha512-+hhVICbnp+rlzZMgxXenpvTxpuvA67Bfgtt+O9WOE5jo7w/dyiF1VmoZVIHvP2EkUjsyKyTwYKlLhA+j47m1Ew==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/undertaker/node_modules/fast-levenshtein": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", + "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==", + "dev": true, "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 - } + "fastest-levenshtein": "^1.0.7" } }, - "union-value": { + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, - "requires": { + "dependencies": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "unique-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", - "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", - "dev": true + "node_modules/unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dev": true, + "dependencies": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } }, - "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, - "requires": { - "crypto-random-string": "^1.0.0" + "engines": { + "node": ">= 10.0.0" } }, - "unpipe": { + "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } }, - "unset-value": { + "node_modules/unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dev": true, - "requires": { + "dependencies": { "has-value": "^0.3.1", "isobject": "^3.0.0" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dev": true, "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", - "dev": true + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "upath": { + "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "update-notifier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", - "dev": true, - "requires": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "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" - } - }, - "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" - } - } + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" } }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" - }, + "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": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - } + "punycode": "^2.1.0" } }, - "urix": { + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, - "url": { + "node_modules/url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "requires": { + "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true, - "requires": { - "prepend-http": "^1.0.1" + "engines": { + "node": ">=0.10.0" } }, - "url-regex": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/url-regex/-/url-regex-3.2.0.tgz", - "integrity": "sha1-260eDJ4p4QXdCx8J9oYvf9tIJyQ=", - "requires": { - "ip-regex": "^1.0.1" + "node_modules/utif2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/utif2/-/utif2-4.1.0.tgz", + "integrity": "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==", + "dependencies": { + "pako": "^1.0.11" } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", - "dev": true + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, - "utils-merge": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", - "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } }, - "uuid": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", - "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=" + "node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } }, - "v8flags": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", - "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "node_modules/v8flags": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz", + "integrity": "sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==", "dev": true, - "requires": { - "user-home": "^1.1.1" + "engines": { + "node": ">= 10.13.0" } }, - "validate-npm-package-license": { + "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, - "requires": { + "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, - "validator": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/validator/-/validator-9.4.1.tgz", - "integrity": "sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA==" + "node_modules/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/value-or-function": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-4.0.0.tgz", + "integrity": "sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } }, - "vary": { + "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "node_modules/vinyl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz", + "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==", + "dev": true, + "dependencies": { + "clone": "^2.1.2", + "clone-stats": "^1.0.0", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" } }, - "vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - }, - "vinyl-fs": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", - "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", - "dev": true, - "requires": { - "defaults": "^1.0.0", - "glob-stream": "^3.1.5", - "glob-watcher": "^0.0.6", - "graceful-fs": "^3.0.0", - "mkdirp": "^0.5.0", - "strip-bom": "^1.0.0", - "through2": "^0.6.1", - "vinyl": "^0.4.0" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "requires": { - "natives": "^1.1.3" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true + "node_modules/vinyl-contents": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-contents/-/vinyl-contents-2.0.0.tgz", + "integrity": "sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q==", + "dev": true, + "dependencies": { + "bl": "^5.0.0", + "vinyl": "^3.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-contents/node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/vinyl-contents/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "strip-bom": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", - "dev": true, - "requires": { - "first-chunk-stream": "^1.0.0", - "is-utf8": "^0.2.0" - } + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/vinyl-contents/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } + { + "type": "consulting", + "url": "https://feross.org/support" } + ] + }, + "node_modules/vinyl-contents/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/vinyl-contents/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "requires": { - "isexe": "^2.0.0" + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "widest-line": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "node_modules/vinyl-fs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-4.0.0.tgz", + "integrity": "sha512-7GbgBnYfaquMk3Qu9g22x000vbYkOex32930rBnc3qByw6HfMEAoELjCjoJv4HuEQxHAurT+nvMHm6MnJllFLw==", + "dev": true, + "dependencies": { + "fs-mkdirp-stream": "^2.0.1", + "glob-stream": "^8.0.0", + "graceful-fs": "^4.2.11", + "iconv-lite": "^0.6.3", + "is-valid-glob": "^1.0.0", + "lead": "^4.0.0", + "normalize-path": "3.0.0", + "resolve-options": "^2.0.0", + "stream-composer": "^1.0.2", + "streamx": "^2.14.0", + "to-through": "^3.0.0", + "value-or-function": "^4.0.0", + "vinyl": "^3.0.0", + "vinyl-sourcemap": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-fs/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, - "requires": { - "string-width": "^2.1.1" + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vinyl-sourcemap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-2.0.0.tgz", + "integrity": "sha512-BAEvWxbBUXvlNoFQVFVHpybBbjW1r03WhohJzJDSfgrrK5xVYIDTan6xN14DlyImShgDRv2gl9qhM6irVMsV0Q==", + "dev": true, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "convert-source-map": "^2.0.0", + "graceful-fs": "^4.2.10", + "now-and-later": "^3.0.0", + "streamx": "^2.12.5", + "vinyl": "^3.0.0", + "vinyl-contents": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "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 + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } }, - "wrap-ansi": { + "node_modules/webidl-conversions": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", - "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^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, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0" - }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", "dev": true }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "requires": { - "mkdirp": "^0.5.1" + "engines": { + "node": ">=0.10.0" } }, - "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "x-xss-protection": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.0.0.tgz", - "integrity": "sha1-iYr7k4abJGYc+cUvnujbjtB2Tdk=" + "node_modules/wrap-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" + } }, - "xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "node_modules/wrap-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/wrap-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 }, - "xhr": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz", - "integrity": "sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==", - "requires": { - "global": "~4.3.0", + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dependencies": { + "global": "~4.4.0", "is-function": "^1.0.1", "parse-headers": "^2.0.0", "xtend": "^4.0.0" } }, - "xml-parse-from-string": { + "node_modules/xml-parse-from-string": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", - "integrity": "sha1-qQKekp09vN7RafPG4oI42VpdWig=" + "integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==" }, - "xml2js": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", - "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", - "requires": { + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dependencies": { "sax": ">=0.6.0", - "xmlbuilder": "^4.1.0" + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" } }, - "xmlbuilder": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", - "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", - "requires": { - "lodash": "^4.0.0" + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" } }, - "xtend": { + "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 392caf0..4f2f5df 100644 --- a/package.json +++ b/package.json @@ -10,54 +10,51 @@ "cmt": "git-cz", "deploy": "now && now alias", "serve": "cross-env NODE_ENV=development gulp", - "start": "node src/index.js" + "start": "node src/index.js", + "format": "prettier --single-quote --trailing-comma none --tab-width=2 --write \"src/**/*.js\"" }, "devDependencies": { - "commitizen": "2.10.1", - "cross-env": "5.0.5", - "cz-conventional-changelog": "2.1.0", - "eslint": "4.19.1", - "eslint-config-semistandard": "12.0.1", - "eslint-config-standard": "10.2.1", - "eslint-plugin-import": "2.10.0", - "eslint-plugin-node": "6.0.1", - "eslint-plugin-promise": "3.7.0", - "eslint-plugin-standard": "3.1.0", - "gulp": "3.9.1", - "gulp-eslint": "4.0.0", - "gulp-nodemon": "2.2.1", - "husky": "1.0.0-rc.13", - "lint-staged": "7.2.2", - "prettier": "1.14.2" + "@eslint/js": "^9.7.0", + "commitizen": "4.3.0", + "cross-env": "7.0.3", + "cz-conventional-changelog": "3.3.0", + "eslint": "^9.7.0", + "globals": "^15.8.0", + "gulp": "5.0.0", + "gulp-eslint-new": "^2.2.0", + "gulp-nodemon": "^2.2.1", + "husky": "9.1.1", + "lint-staged": "15.2.7", + "prettier": "3.3.3" }, "dependencies": { - "aws-sdk": "2.94.0", - "axios": "0.18.0", + "aws-sdk": "2.1660.0", + "axios": "1.7.2", "bcrypt-nodejs": "0.0.3", - "body-parser": "1.17.2", - "cors": "2.8.4", - "dotenv": "4.0.0", - "express": "4.15.3", - "form-data": "2.3.2", - "freemail": "1.5.0", - "google-auth-library": "0.10.0", - "helmet": "3.8.1", - "ip": "1.1.5", - "jimp": "0.2.28", - "jsonwebtoken": "7.4.1", - "lodash": "4.17.4", - "moment": "2.18.1", - "moment-timezone": "0.5.21", + "body-parser": "1.20.2", + "cors": "2.8.5", + "dotenv": "16.4.5", + "express": "4.19.2", + "form-data": "4.0.0", + "freemail": "1.7.0", + "google-auth-library": "9.11.0", + "helmet": "7.1.0", + "ip": "2.0.1", + "jimp": "0.22.12", + "jsonwebtoken": "9.0.2", + "lodash": "4.17.21", + "moment": "2.30.1", + "moment-timezone": "0.5.45", "mongodb-uri": "0.9.7", - "mongoose": "5.3.2", - "morgan": "1.8.2", + "mongoose": "8.5.1", + "morgan": "1.10.0", "multer": "1.3.0", - "nodemailer": "4.0.1", + "nodemailer": "6.9.14", "now": "11.4.6", - "randomstring": "1.1.5", + "randomstring": "1.3.0", "raven": "2.6.0", - "speakingurl": "14.0.0", - "validator": "9.4.1" + "speakingurl": "14.0.1", + "validator": "13.12.0" }, "lint-staged": { "src/**/*.{js}": [ @@ -78,5 +75,8 @@ "hooks": { "pre-commit": "lint-staged" } + }, + "overrides": { + "graceful-fs": "^4.2.11" } } diff --git a/src/helpers/constants.js b/src/helpers/constants.js index 53eeef5..72f82c7 100644 --- a/src/helpers/constants.js +++ b/src/helpers/constants.js @@ -1,129 +1,129 @@ -module.exports = { - languages: ['en', 'es'], - placesTypes: [ - 'accounting', - 'airport', - 'amusement_park', - 'aquarium', - 'art_gallery', - 'atm', - 'bakery', - 'bank', - 'bar', - 'beauty_salon', - 'bicycle_store', - 'book_store', - 'bowling_alley', - 'bus_station', - 'cafe', - 'campground', - 'car_dealer', - 'car_rental', - 'car_repair', - 'car_wash', - 'casino', - 'cemetery', - 'church', - 'city_hall', - 'clothing_store', - 'convenience_store', - 'courthouse', - 'dentist', - 'department_store', - 'doctor', - 'electrician', - 'electronics_store', - 'embassy', - 'establishment', - 'fire_station', - 'florist', - 'funeral_home', - 'furniture_store', - 'gas_station', - 'gym', - 'hair_care', - 'hardware_store', - 'hindu_temple', - 'home_goods_store', - 'hospital', - 'insurance_agency', - 'jewelry_store', - 'laundry', - 'lawyer', - 'library', - 'liquor_store', - 'local_government_office', - 'locksmith', - 'lodging', - 'meal_delivery', - 'meal_takeaway', - 'mosque', - 'movie_rental', - 'movie_theater', - 'moving_company', - 'museum', - 'night_club', - 'painter', - 'park', - 'parking', - 'pet_store', - 'pharmacy', - 'physiotherapist', - 'plumber', - 'police', - 'post_office', - 'real_estate_agency', - 'restaurant', - 'roofing_contractor', - 'rv_park', - 'school', - 'shoe_store', - 'shopping_mall', - 'spa', - 'stadium', - 'storage', - 'store', - 'subway_station', - 'synagogue', - 'taxi_stand', - 'train_station', - 'transit_station', - 'travel_agency', - 'university', - 'veterinary_care', - 'zoo' - ], - directionsTypes: [ - 'administrative_area_level_1', - 'administrative_area_level_2', - 'administrative_area_level_3', - 'administrative_area_level_4', - 'administrative_area_level_5', - 'colloquial_area', - 'country', - 'finance', - 'floor', - 'geocode', - 'intersection', - 'locality', - 'natural_feature', - 'neighborhood', - 'place_of_worship', - 'political', - 'postal_code', - 'postal_code_prefix', - 'postal_code_suffix', - 'postal_town', - 'premise', - 'route', - 'street_address', - 'street_number', - 'sublocality', - 'sublocality_level_5', - 'sublocality_level_4', - 'sublocality_level_3', - 'sublocality_level_2', - 'sublocality_level_1', - 'subpremise' - ] -}; +module.exports = { + languages: ['en', 'es'], + placesTypes: [ + 'accounting', + 'airport', + 'amusement_park', + 'aquarium', + 'art_gallery', + 'atm', + 'bakery', + 'bank', + 'bar', + 'beauty_salon', + 'bicycle_store', + 'book_store', + 'bowling_alley', + 'bus_station', + 'cafe', + 'campground', + 'car_dealer', + 'car_rental', + 'car_repair', + 'car_wash', + 'casino', + 'cemetery', + 'church', + 'city_hall', + 'clothing_store', + 'convenience_store', + 'courthouse', + 'dentist', + 'department_store', + 'doctor', + 'electrician', + 'electronics_store', + 'embassy', + 'establishment', + 'fire_station', + 'florist', + 'funeral_home', + 'furniture_store', + 'gas_station', + 'gym', + 'hair_care', + 'hardware_store', + 'hindu_temple', + 'home_goods_store', + 'hospital', + 'insurance_agency', + 'jewelry_store', + 'laundry', + 'lawyer', + 'library', + 'liquor_store', + 'local_government_office', + 'locksmith', + 'lodging', + 'meal_delivery', + 'meal_takeaway', + 'mosque', + 'movie_rental', + 'movie_theater', + 'moving_company', + 'museum', + 'night_club', + 'painter', + 'park', + 'parking', + 'pet_store', + 'pharmacy', + 'physiotherapist', + 'plumber', + 'police', + 'post_office', + 'real_estate_agency', + 'restaurant', + 'roofing_contractor', + 'rv_park', + 'school', + 'shoe_store', + 'shopping_mall', + 'spa', + 'stadium', + 'storage', + 'store', + 'subway_station', + 'synagogue', + 'taxi_stand', + 'train_station', + 'transit_station', + 'travel_agency', + 'university', + 'veterinary_care', + 'zoo' + ], + directionsTypes: [ + 'administrative_area_level_1', + 'administrative_area_level_2', + 'administrative_area_level_3', + 'administrative_area_level_4', + 'administrative_area_level_5', + 'colloquial_area', + 'country', + 'finance', + 'floor', + 'geocode', + 'intersection', + 'locality', + 'natural_feature', + 'neighborhood', + 'place_of_worship', + 'political', + 'postal_code', + 'postal_code_prefix', + 'postal_code_suffix', + 'postal_town', + 'premise', + 'route', + 'street_address', + 'street_number', + 'sublocality', + 'sublocality_level_5', + 'sublocality_level_4', + 'sublocality_level_3', + 'sublocality_level_2', + 'sublocality_level_1', + 'subpremise' + ] +}; diff --git a/src/helpers/db-connector.js b/src/helpers/db-connector.js index 9ee3db3..183145d 100644 --- a/src/helpers/db-connector.js +++ b/src/helpers/db-connector.js @@ -1,106 +1,97 @@ -const mongoose = require('mongoose'); -const mongoUri = require('mongodb-uri'); - -mongoose.Promise = global.Promise; - -const delayToReconnect = 1000; -let disconnecting; -let initialized = false; -const mongodbURI = process.env.MONGODB_URI; -const dbName = mongoUri.parse(mongodbURI).database; -const options = { - connectTimeoutMS: 30000, - keepAlive: 120, - useCreateIndex: true, - useNewUrlParser: true -}; - -function logging(db) { - db.on('connected', () => - console.log(`Database connection to ${dbName} established`) - ); - db.on('open', () => console.log(`Database connection to ${dbName} opened`)); - db.on('disconnected', () => { - if (disconnecting !== true) { - console.log(`Database connection to ${dbName} lost`); - } - }); - db.on('error', err => { - console.log(`Database connection to ${dbName} error`); - throw err; - }); -} - -function open() { - console.log(`Opening database connection to ${dbName}...`); - mongoose.connect( - mongodbURI, - options - ); -} - -function reconnection(db) { - let timer; - - function reconnect() { - timer = false; - open(db); - } - - function clear() { - if (timer) { - clearTimeout(timer); - } - timer = false; - } - - function schedule() { - if (disconnecting) { - console.log(`Database connection to ${dbName} explicitly shut down`); - return; - } - - if (timer) { - clearTimeout(timer); - } - timer = setTimeout(reconnect, delayToReconnect); - } - - db.on('disconnected', schedule); - db.on('connected', clear); -} - -function connect(done) { - const db = mongoose.connection; - - if (initialized === false) { - initialized = true; - logging(db); - reconnection(db); - } - - open(); - - db.once('connected', done); -} - -function disconnect(done) { - const db = mongoose.connection; - - function disconnected() { - disconnecting = false; - if (done) { - done(); - } - } - - if (db.readyState !== 0) { - disconnecting = true; - db.once('disconnected', disconnected); - db.close(); - } -} - -connect.disconnect = disconnect; - -module.exports = connect; +const mongoose = require('mongoose'); +const mongoUri = require('mongodb-uri'); + +mongoose.Promise = global.Promise; + +const delayToReconnect = 1000; +let disconnecting; +let initialized = false; +const mongodbURI = process.env.MONGODB_URI; +const dbName = mongoUri.parse(mongodbURI).database; + +function logging(db) { + db.on('connected', () => + console.log(`Database connection to ${dbName} established`) + ); + db.on('open', () => console.log(`Database connection to ${dbName} opened`)); + db.on('disconnected', () => { + if (disconnecting !== true) { + console.log(`Database connection to ${dbName} lost`); + } + }); + db.on('error', (err) => { + console.log(`Database connection to ${dbName} error`); + throw err; + }); +} + +function open() { + console.log(`Opening database connection to ${dbName}...`); + mongoose.connect(mongodbURI); +} + +function reconnection(db) { + let timer; + + function reconnect() { + timer = false; + open(db); + } + + function clear() { + if (timer) { + clearTimeout(timer); + } + timer = false; + } + + function schedule() { + if (disconnecting) { + console.log(`Database connection to ${dbName} explicitly shut down`); + return; + } + + if (timer) { + clearTimeout(timer); + } + timer = setTimeout(reconnect, delayToReconnect); + } + + db.on('disconnected', schedule); + db.on('connected', clear); +} + +function connect(done) { + const db = mongoose.connection; + + if (initialized === false) { + initialized = true; + logging(db); + reconnection(db); + } + + open(); + + db.once('connected', done); +} + +function disconnect(done) { + const db = mongoose.connection; + + function disconnected() { + disconnecting = false; + if (done) { + done(); + } + } + + if (db.readyState !== 0) { + disconnecting = true; + db.once('disconnected', disconnected); + db.close(); + } +} + +connect.disconnect = disconnect; + +module.exports = connect; diff --git a/src/helpers/index.js b/src/helpers/index.js index 3445d7f..94f26fc 100644 --- a/src/helpers/index.js +++ b/src/helpers/index.js @@ -1,106 +1,109 @@ -const aws = require('aws-sdk'); -const { camelCase } = require('lodash'); -const jwt = require('jsonwebtoken'); -const { mapKeys, pickBy } = require('lodash'); -const nodemailer = require('nodemailer'); -const { snakeCase } = require('lodash'); - -const { User } = require('../models/user'); - -module.exports = { - cleanSpaces(string) { - return string.replace(/\s+/g, ' ').trim(); - }, - deleteUnusedProperties(obj) { - return pickBy(obj, prop => prop); - }, - isAuthenticated: ({ isOptional }) => async (req, res, next) => { - const authorizationHeader = req.headers.authorization; - let token; - - if (authorizationHeader) { - token = authorizationHeader.split(' ')[1]; - } - - if (token) { - let decoded; - try { - decoded = await jwt.verify(token, process.env.JWT_SECRET); - } catch (err) { - return res.status(401).json({ general: 'Failed to authenticate' }); - } - - let user; - try { - user = await User.findOne({ - _id: decoded.userId, - isArchived: false - }).select( - '-__v -createdAt -isAdmin -isArchived -isBlocked -hashedPassword -updatedAt' - ); - } catch (err) { - console.log( - `User ${decoded.userId} failed to be found at authenticate` - ); - return next(err); - } - - if (user) { - req.user = user; - - if ( - (isOptional && req.user && req.user.isBlocked) || - (!isOptional && req.user.isBlocked) - ) { - return res.status(423).json({ general: 'You are blocked' }); - } - - return next(); - } - - return res.status(404).json({ general: 'User not found' }); - } - - if (isOptional) { - return next(); - } - - return res.status(401).json({ general: 'No token provided' }); - }, - isNumber(number) { - return !isNaN(parseFloat(number)) && isFinite(number); - }, - mapCamelCaseKeys(obj) { - return mapKeys(obj, (value, key) => camelCase(key)); - }, - mapSnakeCaseKeys(obj) { - return mapKeys(obj, (value, key) => snakeCase(key)); - }, - removeSpaces(string) { - return string.replace(/\s/g, ''); - }, - sendEmail({ - senderEmail = process.env.SENDER_EMAIL, - receiversEmails, - subject, - htmlContent, - textContent - }) { - const transporter = nodemailer.createTransport({ - SES: new aws.SES({ - apiVersion: '2010-12-01' - }) - }); - - return transporter.sendMail({ - from: `"AXS Map" <${senderEmail}>`, - to: receiversEmails.join(', '), - subject, - text: textContent, - html: htmlContent - }); - }, - toJSON(obj) { - return JSON.parse(JSON.stringify(obj)); - } -}; +const aws = require('aws-sdk'); +const { camelCase } = require('lodash'); +const jwt = require('jsonwebtoken'); +const { mapKeys, pickBy } = require('lodash'); +const nodemailer = require('nodemailer'); +const { snakeCase } = require('lodash'); + +const { User } = require('../models/user'); + +module.exports = { + cleanSpaces(string) { + return string.replace(/\s+/g, ' ').trim(); + }, + deleteUnusedProperties(obj) { + return pickBy(obj, (prop) => prop); + }, + isAuthenticated: + ({ isOptional }) => + async (req, res, next) => { + const authorizationHeader = req.headers.authorization; + let token; + + if (authorizationHeader) { + token = authorizationHeader.split(' ')[1]; + } + + if (token) { + let decoded; + try { + decoded = await jwt.verify(token, process.env.JWT_SECRET); + } catch (err) { + console.log(err); + return res.status(401).json({ general: 'Failed to authenticate' }); + } + + let user; + try { + user = await User.findOne({ + _id: decoded.userId, + isArchived: false + }).select( + '-__v -createdAt -isAdmin -isArchived -isBlocked -hashedPassword -updatedAt' + ); + } catch (err) { + console.log( + `User ${decoded.userId} failed to be found at authenticate` + ); + return next(err); + } + + if (user) { + req.user = user; + + if ( + (isOptional && req.user && req.user.isBlocked) || + (!isOptional && req.user.isBlocked) + ) { + return res.status(423).json({ general: 'You are blocked' }); + } + + return next(); + } + + return res.status(404).json({ general: 'User not found' }); + } + + if (isOptional) { + return next(); + } + + return res.status(401).json({ general: 'No token provided' }); + }, + isNumber(number) { + return !isNaN(parseFloat(number)) && isFinite(number); + }, + mapCamelCaseKeys(obj) { + return mapKeys(obj, (value, key) => camelCase(key)); + }, + mapSnakeCaseKeys(obj) { + return mapKeys(obj, (value, key) => snakeCase(key)); + }, + removeSpaces(string) { + return string.replace(/\s/g, ''); + }, + sendEmail({ + senderEmail = process.env.SENDER_EMAIL, + receiversEmails, + subject, + htmlContent, + textContent + }) { + const transporter = nodemailer.createTransport({ + SES: new aws.SES({ + apiVersion: '2010-12-01' + }) + }); + + return transporter.sendMail({ + from: `"AXS Map" <${senderEmail}>`, + to: receiversEmails.join(', '), + subject, + text: textContent, + html: htmlContent + }); + }, + toJSON(obj) { + return JSON.parse(JSON.stringify(obj)); + } +}; diff --git a/src/helpers/venue-review-summary.js b/src/helpers/venue-review-summary.js index e752584..6fc30b5 100644 --- a/src/helpers/venue-review-summary.js +++ b/src/helpers/venue-review-summary.js @@ -8,8 +8,8 @@ function assignFromYesNo(venueField) { // Mongoose hasOwnProperty test issues if ( venueField && - venueField.hasOwnProperty('yes') && - venueField.hasOwnProperty('no') && + 'yes' in venueField && + 'no' in venueField && !(venueField.yes === 0 && venueField.no === 0) ) { if (venueField.yes >= venueField.no) { @@ -23,12 +23,10 @@ function assignFromYesNo(venueField) { } function assignFromSteps(stepField) { - let moreThanTwo = stepField.hasOwnProperty('moreThanTwo') - ? stepField.moreThanTwo - : 0; - let two = stepField.hasOwnProperty('two') ? stepField.two : 0; - let one = stepField.hasOwnProperty('one') ? stepField.one : 0; - let zero = stepField.hasOwnProperty('zero') ? stepField.zero : 0; + let moreThanTwo = 'moreThanTwo' in stepField ? stepField.moreThanTwo : 0; + let two = 'two' in stepField ? stepField.two : 0; + let one = 'one' in stepField ? stepField.one : 0; + let zero = 'zero' in stepField ? stepField.zero : 0; if (moreThanTwo === 0 && two === 0 && one === 0 && zero === 0) { return null; @@ -95,7 +93,7 @@ module.exports = { //console.log('in calculateRatingLevel, select venue data: ', venueData); let sectionLogic, ratingDefinition; - if (reviewSummaryLogic.hasOwnProperty(sectionName)) { + if (sectionName in reviewSummaryLogic) { //valid values: entrance, restroom, interior sectionLogic = reviewSummaryLogic[sectionName]; } else { @@ -108,37 +106,37 @@ module.exports = { let ratingLevel, ratingGlyphs; const ratingLevels = ['alert', 'caution', 'accessible']; - for (rl = 0; rl < ratingLevels.length; rl++) { + for (let rl = 0; rl < ratingLevels.length; rl++) { if ( - sectionLogic.hasOwnProperty(ratingLevels[rl]) && + ratingLevels[rl] in sectionLogic && sectionLogic[ratingLevels[rl]].length > 0 ) { //level loop - for (idx = 0; idx < sectionLogic[ratingLevels[rl]].length; idx++) { + for (let idx = 0; idx < sectionLogic[ratingLevels[rl]].length; idx++) { ratingDefinition = sectionLogic[ratingLevels[rl]][idx]; let ratingDefinitionMatch = false; if ( - ratingDefinition.hasOwnProperty('field') && - venueData.hasOwnProperty(ratingDefinition.field) + 'field' in ratingDefinition && + ratingDefinition.field in venueData ) { if ( - (ratingDefinition.hasOwnProperty('matchValue') && + ('matchValue' in ratingDefinition && venueData[ratingDefinition.field] === ratingDefinition.matchValue) || - (ratingDefinition.hasOwnProperty('notMatchValue') && + ('notMatchValue' in ratingDefinition && venueData[ratingDefinition.field] !== ratingDefinition.notMatchValue) ) { ratingDefinitionMatch = true; } - } else if (ratingDefinition.hasOwnProperty('fields')) { + } else if ('fields' in ratingDefinition) { let fieldMatchCount = 0; - for (field of ratingDefinition.fields) { + for (let field of ratingDefinition.fields) { if ( - (ratingDefinition.hasOwnProperty('matchValue') && + ('matchValue' in ratingDefinition && venueData[field] === ratingDefinition.matchValue) || - (ratingDefinition.hasOwnProperty('notMatchValue') && + ('notMatchValue' in ratingDefinition && venueData[field] !== ratingDefinition.notMatchValue) ) { fieldMatchCount++; @@ -150,21 +148,18 @@ module.exports = { } } - if ( - ratingDefinitionMatch === true && - ratingDefinition.hasOwnProperty('and') - ) { + if (ratingDefinitionMatch === true && 'and' in ratingDefinition) { //console.log('Evaluate AND condition in ' + sectionName); if ( - ratingDefinition.and.hasOwnProperty('field') && - venueData.hasOwnProperty(ratingDefinition.and.field) + 'field' in ratingDefinition.and && + ratingDefinition.and.field in venueData ) { //evaluate 'and' condition depending on match or noMatch value - if (ratingDefinition.and.hasOwnProperty('matchValue')) { + if ('matchValue' in ratingDefinition.and) { ratingDefinitionMatch = venueData[ratingDefinition.and.field] == ratingDefinition.and.matchValue; - } else if (ratingDefinition.and.hasOwnProperty('notMatchValue')) { + } else if ('notMatchValue' in ratingDefinition.and) { ratingDefinitionMatch = venueData[ratingDefinition.and.field] !== ratingDefinition.and.notMatchValue; @@ -202,9 +197,9 @@ module.exports = { //console.log('ratingLevel not set: ', sectionLogic); ratingLevel = 0; ratingGlyphs = - sectionLogic.hasOwnProperty('default') && + 'default' in sectionLogic && sectionLogic.default.length > 0 && - sectionLogic.default[0].hasOwnProperty('showGlyph') + 'showGlyph' in sectionLogic.default[0] ? sectionLogic.default[0].showGlyph : ''; } diff --git a/src/index.js b/src/index.js index f75263b..6c650e1 100644 --- a/src/index.js +++ b/src/index.js @@ -1,81 +1,81 @@ -const fs = require('fs'); -const https = require('https'); - -const bodyParser = require('body-parser'); -const cors = require('cors'); -const express = require('express'); -const helmet = require('helmet'); -const ip = require('ip'); -const morgan = require('morgan'); -const raven = require('raven'); - -// Fill process.env with environment variables -require('dotenv').config(); -//console.log(process.env) - -const port = process.env.PORT || 8000; - -const connectToDB = require('./helpers/db-connector'); -const routes = require('./routes'); - -function connectedToDB() { - const app = express(); - - raven - .config(process.env.SENTRY_URL, { - captureUnhandledRejections: true - }) - .install(); - - // Middlewares - app.use(raven.requestHandler()); - app.use(cors()); - app.use(morgan('dev')); - app.use(bodyParser.json()); - app.use(helmet()); - - // Routes - app.set('strict routing', true); - app.use('/', routes); - - // Error handling - app.use(raven.errorHandler()); - app.use((req, res, _next) => res.status(404).json({ general: 'Not found' })); - app.use((err, req, res, _next) => { - if (err instanceof SyntaxError) { - return res.status(400).json({ general: 'Invalid JSON format' }); - } - - console.error(err.stack); - return res.status(500).json({ general: 'Something went wrong' }); - }); - - process.on('uncaughtException', err => { - console.error(err); - raven.captureException(err); - }); - process.on('unhandledRejection', err => { - console.error(err); - raven.captureException(err); - }); - - // App Initialization - if (process.env.NODE_ENV === 'production') { - console.log(`Listening on http://${ip.address()}:${port}`); - app.listen(port); - } else { - https - .createServer( - { - key: fs.readFileSync('./certificates/server.key'), - cert: fs.readFileSync('./certificates/server.crt') - }, - app - ) - .listen(port, () => - console.log(`Listening on https://${ip.address()}:${port}`) - ); - } -} - -connectToDB(connectedToDB); +const fs = require('fs'); +const https = require('https'); + +const bodyParser = require('body-parser'); +const cors = require('cors'); +const express = require('express'); +const helmet = require('helmet'); +const ip = require('ip'); +const morgan = require('morgan'); +const raven = require('raven'); + +// Fill process.env with environment variables +require('dotenv').config(); +//console.log(process.env) + +const port = process.env.PORT || 8000; + +const connectToDB = require('./helpers/db-connector'); +const routes = require('./routes'); + +function connectedToDB() { + const app = express(); + + raven + .config(process.env.SENTRY_URL, { + captureUnhandledRejections: true + }) + .install(); + + // Middlewares + app.use(raven.requestHandler()); + app.use(cors()); + app.use(morgan('dev')); + app.use(bodyParser.json()); + app.use(helmet()); + + // Routes + app.set('strict routing', true); + app.use('/', routes); + + // Error handling + app.use(raven.errorHandler()); + app.use((req, res) => res.status(404).json({ general: 'Not found' })); + app.use((err, req, res) => { + if (err instanceof SyntaxError) { + return res.status(400).json({ general: 'Invalid JSON format' }); + } + + console.error(err.stack); + return res.status(500).json({ general: 'Something went wrong' }); + }); + + process.on('uncaughtException', (err) => { + console.error(err); + raven.captureException(err); + }); + process.on('unhandledRejection', (err) => { + console.error(err); + raven.captureException(err); + }); + + // App Initialization + if (process.env.NODE_ENV === 'production') { + console.log(`Listening on http://${ip.address()}:${port}`); + app.listen(port); + } else { + https + .createServer( + { + key: fs.readFileSync('./certificates/server.key'), + cert: fs.readFileSync('./certificates/server.crt') + }, + app + ) + .listen(port, () => + console.log(`Listening on https://${ip.address()}:${port}`) + ); + } +} + +connectToDB(connectedToDB); diff --git a/src/models/activation-ticket.js b/src/models/activation-ticket.js index 621d2c0..1fa8760 100644 --- a/src/models/activation-ticket.js +++ b/src/models/activation-ticket.js @@ -1,48 +1,48 @@ -const mongoose = require('mongoose'); - -const activationTicketSchema = new mongoose.Schema( - { - email: { - type: String, - maxlength: [254, 'Should have less than 255 characters'], - required: [true, 'Is required'] - }, - expiresAt: { - type: Date, - required: [true, 'Is required'] - }, - key: { - type: String, - maxlength: [75, 'Should have less than 76 characters'], - required: [true, 'Is required'] - }, - userData: { - firstName: { - type: String, - maxlength: [24, 'Should have less than 25 characters'] - }, - isSubscribed: { - type: Boolean - }, - lastName: { - type: String, - maxlength: [36, 'Should have less than 37 characters'] - }, - password: { - type: String, - maxlength: [30, 'Should have less than 31 characters'], - minlength: [8, 'Should have more than 7 characters'] - }, - username: { - type: String, - maxlength: [67, 'Should have less than 68 characters'] - } - } - }, - { timestamps: true } -); - -module.exports = { - ActivationTicket: mongoose.model('ActivationTicket', activationTicketSchema), - activationTicketSchema -}; +const mongoose = require('mongoose'); + +const activationTicketSchema = new mongoose.Schema( + { + email: { + type: String, + maxlength: [254, 'Should have less than 255 characters'], + required: [true, 'Is required'] + }, + expiresAt: { + type: Date, + required: [true, 'Is required'] + }, + key: { + type: String, + maxlength: [75, 'Should have less than 76 characters'], + required: [true, 'Is required'] + }, + userData: { + firstName: { + type: String, + maxlength: [24, 'Should have less than 25 characters'] + }, + isSubscribed: { + type: Boolean + }, + lastName: { + type: String, + maxlength: [36, 'Should have less than 37 characters'] + }, + password: { + type: String, + maxlength: [30, 'Should have less than 31 characters'], + minlength: [8, 'Should have more than 7 characters'] + }, + username: { + type: String, + maxlength: [67, 'Should have less than 68 characters'] + } + } + }, + { timestamps: true } +); + +module.exports = { + ActivationTicket: mongoose.model('ActivationTicket', activationTicketSchema), + activationTicketSchema +}; diff --git a/src/models/event.js b/src/models/event.js index a767260..8c4b586 100644 --- a/src/models/event.js +++ b/src/models/event.js @@ -1,141 +1,141 @@ -const mongoose = require('mongoose'); - -const eventSchema = new mongoose.Schema( - { - address: { - type: String, - maxlength: [200, 'Should be less than 201 characters'], - required: [true, 'Is required'] - }, - description: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - donationAmounts: { - type: [ - { - value: { - type: Number, - default: 5, - max: [10000, 'Should be less than 10001'], - min: [5, 'Should be greater than 4'] - } - } - ] - }, - donationEnabled: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - donationGoal: { - type: Number, - default: 10, - max: [100000, 'Should be less than 100001'], - min: [10, 'Should be greater than 9'] - }, - donationId: { - type: String, - default: '' - }, - endDate: { - type: Date, - required: [true, 'Is required'] - }, - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isOpen: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - location: { - type: { - type: String, - default: 'Point' - }, - coordinates: [Number] - }, - managers: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ], - required: [true, 'Is required'] - }, - name: { - type: String, - maxlength: [100, 'Should be less than 101 characters'], - required: [true, 'Is required'] - }, - participants: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ] - }, - participantsGoal: { - type: Number, - max: [1000, 'Should be less than 1001'], - min: [1, 'Should be greater than 0'], - required: [true, 'Is required'] - }, - poster: { - type: String, - default: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - reviewsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - }, - reviewsGoal: { - type: Number, - max: [10000, 'Should be less than 10001'], - min: [1, 'Should be greater than 0'] - }, - startDate: { - type: Date, - required: [true, 'Is required'] - }, - teamManager: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - }, - teams: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - } - ], - venue: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Venue' - } - }, - { timestamps: true } -); - -eventSchema.index({ - address: 'text', - name: 'text', - endDate: 1, - reviewsAmount: 1, - startDate: 1 -}); - -module.exports = { - Event: mongoose.model('Event', eventSchema), - eventSchema -}; +const mongoose = require('mongoose'); + +const eventSchema = new mongoose.Schema( + { + address: { + type: String, + maxlength: [200, 'Should be less than 201 characters'], + required: [true, 'Is required'] + }, + description: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + donationAmounts: { + type: [ + { + value: { + type: Number, + default: 5, + max: [10000, 'Should be less than 10001'], + min: [5, 'Should be greater than 4'] + } + } + ] + }, + donationEnabled: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + donationGoal: { + type: Number, + default: 10, + max: [100000, 'Should be less than 100001'], + min: [10, 'Should be greater than 9'] + }, + donationId: { + type: String, + default: '' + }, + endDate: { + type: Date, + required: [true, 'Is required'] + }, + isArchived: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isOpen: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + location: { + type: { + type: String, + default: 'Point' + }, + coordinates: [Number] + }, + managers: { + type: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ], + required: [true, 'Is required'] + }, + name: { + type: String, + maxlength: [100, 'Should be less than 101 characters'], + required: [true, 'Is required'] + }, + participants: { + type: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ] + }, + participantsGoal: { + type: Number, + max: [1000, 'Should be less than 1001'], + min: [1, 'Should be greater than 0'], + required: [true, 'Is required'] + }, + poster: { + type: String, + default: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`, + maxlength: [2000, 'Should be less than 2001 characters'], + required: [true, 'Is required'] + }, + reviewsAmount: { + type: Number, + default: 0, + required: [true, 'Is required'] + }, + reviewsGoal: { + type: Number, + max: [10000, 'Should be less than 10001'], + min: [1, 'Should be greater than 0'] + }, + startDate: { + type: Date, + required: [true, 'Is required'] + }, + teamManager: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + }, + teams: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + } + ], + venue: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Venue' + } + }, + { timestamps: true } +); + +eventSchema.index({ + address: 'text', + name: 'text', + endDate: 1, + reviewsAmount: 1, + startDate: 1 +}); + +module.exports = { + Event: mongoose.model('Event', eventSchema), + eventSchema +}; diff --git a/src/models/password-ticket.js b/src/models/password-ticket.js index 00a4ced..ca98254 100644 --- a/src/models/password-ticket.js +++ b/src/models/password-ticket.js @@ -1,26 +1,26 @@ -const mongoose = require('mongoose'); - -const passwordTicketSchema = new mongoose.Schema( - { - email: { - type: String, - maxlength: [254, 'Should have less than 255 characters'], - required: [true, 'Is required'] - }, - expiresAt: { - type: Date, - required: [true, 'Is required'] - }, - key: { - type: String, - maxlength: [75, 'Should have less than 76 characters'], - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -module.exports = { - PasswordTicket: mongoose.model('PasswordTicket', passwordTicketSchema), - passwordTicketSchema -}; +const mongoose = require('mongoose'); + +const passwordTicketSchema = new mongoose.Schema( + { + email: { + type: String, + maxlength: [254, 'Should have less than 255 characters'], + required: [true, 'Is required'] + }, + expiresAt: { + type: Date, + required: [true, 'Is required'] + }, + key: { + type: String, + maxlength: [75, 'Should have less than 76 characters'], + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +module.exports = { + PasswordTicket: mongoose.model('PasswordTicket', passwordTicketSchema), + passwordTicketSchema +}; diff --git a/src/models/petition.js b/src/models/petition.js index af49041..01f3423 100644 --- a/src/models/petition.js +++ b/src/models/petition.js @@ -1,59 +1,59 @@ -const mongoose = require('mongoose'); - -const petitionSchema = new mongoose.Schema( - { - event: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - }, - message: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - sender: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - }, - state: { - type: String, - default: 'pending', - enum: { - values: ['accepted', 'canceled', 'pending', 'rejected'], - message: 'Should be a valid state' - }, - required: [true, 'Is required'] - }, - team: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - }, - type: { - type: String, - enum: { - values: [ - 'invite-team-event', - 'invite-user-event', - 'invite-user-team', - 'request-team-event', - 'request-user-event', - 'request-user-team' - ], - message: 'Should be a valid type' - }, - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - }, - { timestamps: true } -); - -petitionSchema.index({ createdAt: -1 }); - -module.exports = { - Petition: mongoose.model('Petition', petitionSchema), - petitionSchema -}; +const mongoose = require('mongoose'); + +const petitionSchema = new mongoose.Schema( + { + event: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Event' + }, + message: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + sender: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + }, + state: { + type: String, + default: 'pending', + enum: { + values: ['accepted', 'canceled', 'pending', 'rejected'], + message: 'Should be a valid state' + }, + required: [true, 'Is required'] + }, + team: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + }, + type: { + type: String, + enum: { + values: [ + 'invite-team-event', + 'invite-user-event', + 'invite-user-team', + 'request-team-event', + 'request-user-event', + 'request-user-team' + ], + message: 'Should be a valid type' + }, + required: [true, 'Is required'] + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + }, + { timestamps: true } +); + +petitionSchema.index({ createdAt: -1 }); + +module.exports = { + Petition: mongoose.model('Petition', petitionSchema), + petitionSchema +}; diff --git a/src/models/photo.js b/src/models/photo.js index 6a277a8..37d7049 100644 --- a/src/models/photo.js +++ b/src/models/photo.js @@ -1,66 +1,66 @@ -const mongoose = require('mongoose'); - -const photoSchema = new mongoose.Schema( - { - complaints: [ - { - comments: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - createdAt: { - type: Date, - default: Date.now, - required: [true, 'Is required'] - }, - type: { - type: String, - enum: { - values: [ - 'biased', - 'copyright', - 'inconsistent', - 'offensive', - 'offtopic', - 'other', - 'spam' - ], - general: 'Invalid type of complaint' - }, - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - } - } - ], - fileName: { - type: String, - maxlength: [25, 'Should be less than 26 characters'], - required: [true, 'Is required'] - }, - isAllowed: { - type: Boolean, - default: true, - required: [true, 'Is required'] - }, - url: { - type: String, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -module.exports = { - Photo: mongoose.model('Photo', photoSchema), - photoSchema -}; +const mongoose = require('mongoose'); + +const photoSchema = new mongoose.Schema( + { + complaints: [ + { + comments: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + createdAt: { + type: Date, + default: Date.now, + required: [true, 'Is required'] + }, + type: { + type: String, + enum: { + values: [ + 'biased', + 'copyright', + 'inconsistent', + 'offensive', + 'offtopic', + 'other', + 'spam' + ], + general: 'Invalid type of complaint' + }, + required: [true, 'Is required'] + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + } + } + ], + fileName: { + type: String, + maxlength: [25, 'Should be less than 26 characters'], + required: [true, 'Is required'] + }, + isAllowed: { + type: Boolean, + default: true, + required: [true, 'Is required'] + }, + url: { + type: String, + maxlength: [2000, 'Should be less than 2001 characters'], + required: [true, 'Is required'] + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +module.exports = { + Photo: mongoose.model('Photo', photoSchema), + photoSchema +}; diff --git a/src/models/refresh-token.js b/src/models/refresh-token.js index ac74a06..3ddeffe 100644 --- a/src/models/refresh-token.js +++ b/src/models/refresh-token.js @@ -1,27 +1,27 @@ -const mongoose = require('mongoose'); - -const refreshTokenSchema = new mongoose.Schema( - { - expiresAt: { - type: Date, - required: [true, 'Is required'] - }, - key: { - type: String, - maxlength: [80, 'Should have less than 81 characters'], - required: [true, 'Is required'], - unique: true - }, - userId: { - type: String, - maxlength: [24, 'Should have less than 25 characters'], - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -module.exports = { - RefreshToken: mongoose.model('RefreshToken', refreshTokenSchema), - refreshTokenSchema -}; +const mongoose = require('mongoose'); + +const refreshTokenSchema = new mongoose.Schema( + { + expiresAt: { + type: Date, + required: [true, 'Is required'] + }, + key: { + type: String, + maxlength: [80, 'Should have less than 81 characters'], + required: [true, 'Is required'], + unique: true + }, + userId: { + type: String, + maxlength: [24, 'Should have less than 25 characters'], + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +module.exports = { + RefreshToken: mongoose.model('RefreshToken', refreshTokenSchema), + refreshTokenSchema +}; diff --git a/src/models/review.js b/src/models/review.js index 7ed9617..f719643 100644 --- a/src/models/review.js +++ b/src/models/review.js @@ -1,122 +1,122 @@ -const mongoose = require('mongoose'); - -const reviewSchema = new mongoose.Schema( - { - //new expanded fields - hasPermanentRamp: Boolean, - hasPortableRamp: Boolean, - hasWideEntrance: Boolean, - hasAccessibleTableHeight: Boolean, - hasAccessibleElevator: Boolean, - hasInteriorRamp: Boolean, - hasSwingOutDoor: Boolean, - hasLargeStall: Boolean, - hasSupportAroundToilet: Boolean, - hasLoweredSinks: Boolean, - - //original fields - allowsGuideDog: Boolean, - comments: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - complaints: [ - { - comments: { - type: String, - maxlength: [300, 'Should be less than 30 characters'] - }, - createdAt: { - type: Date, - default: Date.now, - required: [true, 'Is required'] - }, - type: { - type: String, - enum: { - values: [ - 'biased', - 'copyright', - 'inconsistent', - 'offensive', - 'offtopic', - 'other', - 'spam' - ], - general: 'Invalid type of complaint' - }, - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - } - } - ], - - /* - * deprecated 5-star scoring - */ - _entryScore: { - type: Number - //max: [9, 'Should be less than 10'], - //min: [1, 'Should be more than 0'] - }, - _bathroomScore: { - type: Number - //max: [4, 'Should be less than 5'], - //min: [1, 'Should be more than 0'] - }, - _isScoreConverted: { - type: Boolean, - default: false - }, - - event: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - }, - hasParking: Boolean, - hasSecondEntry: Boolean, - hasWellLit: Boolean, - isBanned: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isQuiet: Boolean, - isSpacious: Boolean, - steps: { - type: Number, - max: [3, 'Should be less than 4'], - min: [0, 'Should be more than -1'] - }, - team: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - }, - venue: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Venue', - required: [true, 'Is required'] - }, - voters: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ] - }, - { timestamps: true } -); - -module.exports = { - Review: mongoose.model('Review', reviewSchema), - reviewSchema -}; +const mongoose = require('mongoose'); + +const reviewSchema = new mongoose.Schema( + { + //new expanded fields + hasPermanentRamp: Boolean, + hasPortableRamp: Boolean, + hasWideEntrance: Boolean, + hasAccessibleTableHeight: Boolean, + hasAccessibleElevator: Boolean, + hasInteriorRamp: Boolean, + hasSwingOutDoor: Boolean, + hasLargeStall: Boolean, + hasSupportAroundToilet: Boolean, + hasLoweredSinks: Boolean, + + //original fields + allowsGuideDog: Boolean, + comments: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + complaints: [ + { + comments: { + type: String, + maxlength: [300, 'Should be less than 30 characters'] + }, + createdAt: { + type: Date, + default: Date.now, + required: [true, 'Is required'] + }, + type: { + type: String, + enum: { + values: [ + 'biased', + 'copyright', + 'inconsistent', + 'offensive', + 'offtopic', + 'other', + 'spam' + ], + general: 'Invalid type of complaint' + }, + required: [true, 'Is required'] + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + } + } + ], + + /* + * deprecated 5-star scoring + */ + _entryScore: { + type: Number + //max: [9, 'Should be less than 10'], + //min: [1, 'Should be more than 0'] + }, + _bathroomScore: { + type: Number + //max: [4, 'Should be less than 5'], + //min: [1, 'Should be more than 0'] + }, + _isScoreConverted: { + type: Boolean, + default: false + }, + + event: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Event' + }, + hasParking: Boolean, + hasSecondEntry: Boolean, + hasWellLit: Boolean, + isBanned: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isQuiet: Boolean, + isSpacious: Boolean, + steps: { + type: Number, + max: [3, 'Should be less than 4'], + min: [0, 'Should be more than -1'] + }, + team: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + }, + venue: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Venue', + required: [true, 'Is required'] + }, + voters: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ] + }, + { timestamps: true } +); + +module.exports = { + Review: mongoose.model('Review', reviewSchema), + reviewSchema +}; diff --git a/src/models/team.js b/src/models/team.js index 0d61217..9d96722 100644 --- a/src/models/team.js +++ b/src/models/team.js @@ -1,62 +1,62 @@ -const mongoose = require('mongoose'); - -const teamSchema = new mongoose.Schema( - { - avatar: { - type: String, - default: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/teams/avatars/default.png`, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - description: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - events: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - } - ], - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - managers: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ], - required: [true, 'Is required'] - }, - members: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ], - name: { - type: String, - maxlength: [35, 'Should be less than 36 characters'], - required: [true, 'Is required'] - }, - reviewsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -teamSchema.index({ name: 'text', reviewsAmount: 1 }); - -module.exports = { - Team: mongoose.model('Team', teamSchema), - teamSchema -}; +const mongoose = require('mongoose'); + +const teamSchema = new mongoose.Schema( + { + avatar: { + type: String, + default: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/teams/avatars/default.png`, + maxlength: [2000, 'Should be less than 2001 characters'], + required: [true, 'Is required'] + }, + description: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + events: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'Event' + } + ], + isArchived: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + managers: { + type: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ], + required: [true, 'Is required'] + }, + members: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ], + name: { + type: String, + maxlength: [35, 'Should be less than 36 characters'], + required: [true, 'Is required'] + }, + reviewsAmount: { + type: Number, + default: 0, + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +teamSchema.index({ name: 'text', reviewsAmount: 1 }); + +module.exports = { + Team: mongoose.model('Team', teamSchema), + teamSchema +}; diff --git a/src/models/user.js b/src/models/user.js index e0c9cb9..949b077 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -1,193 +1,193 @@ -const bcrypt = require('bcrypt-nodejs'); -const mongoose = require('mongoose'); - -const userSchema = new mongoose.Schema( - { - avatar: { - type: String, - default: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/users/avatars/default.png`, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - description: { - type: String, - maxlength: [2000, 'Should be less than 2001 characters'] - }, - disabilities: { - type: [String], - default: ['none'], - enum: { - values: [ - 'brain', - 'cognitive', - 'hearing', - 'invisible', - 'none', - 'other', - 'physical', - 'private', - 'psychological', - 'spinal-cord', - 'vision' - ], - general: 'Invalid type of disability' - }, - required: [true, 'Is required'] - }, - email: { - type: String, - maxlength: [254, 'Should be less than 255 characters'] - }, - events: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - } - ], - facebookId: String, - firstName: { - type: String, - maxlength: [24, 'Should be less than 25 characters'], - required: [true, 'Is required'] - }, - gender: { - type: String, - default: 'private', - enum: { - values: ['female', 'male', 'other', 'private', 'transgender'], - general: 'Invalid type of gender' - }, - required: [true, 'Is required'] - }, - googleId: String, - hashedPassword: { - type: String, - maxlength: [256, 'Should be less than 255 characters'] - }, - isAdmin: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isBlocked: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isSubscribed: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - lastName: { - type: String, - maxlength: [36, 'Should be less than 37 characters'], - required: [true, 'Is required'] - }, - language: { - type: String, - default: 'en', - enum: { - values: ['en', 'es'], - general: 'Invalid type of language' - }, - required: [true, 'Is required'] - }, - phone: { - type: String, - maxlength: [50, 'Should be less than 51 characters'] - }, - reviewFieldsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - }, - reviewsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - }, - showDisabilities: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - showEmail: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - showPhone: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - teams: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - } - ], - username: { - type: String, - maxlength: [67, 'Should be less than 68 characters'] - }, - zip: { - type: String, - maxlength: [32, 'Should be less than 33 characters'] - } - }, - { timestamps: true } -); - -userSchema.index( - { - email: 'text', - firstName: 'text', - lastName: 'text', - username: 'text', - reviewsAmount: 1 - }, - { weights: { email: 5, username: 5 } } -); - -function hashPassword(password) { - bcrypt.genSalt(10, (errorOnSaltGeneration, salt) => { - if (errorOnSaltGeneration) { - return false; - } - - bcrypt.hash( - password, - salt, - null, - (errorOnHashingPassword, hashedPassword) => { - if (errorOnHashingPassword) { - return false; - } - - this.hashedPassword = hashedPassword; - return true; - } - ); - }); -} - -function comparePassword(password) { - return bcrypt.compareSync(password, this.hashedPassword); -} - -userSchema.virtual('password').set(hashPassword); -userSchema.methods.comparePassword = comparePassword; - -module.exports = { - User: mongoose.model('User', userSchema), - userSchema -}; +const bcrypt = require('bcrypt-nodejs'); +const mongoose = require('mongoose'); + +const userSchema = new mongoose.Schema( + { + avatar: { + type: String, + default: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/users/avatars/default.png`, + maxlength: [2000, 'Should be less than 2001 characters'], + required: [true, 'Is required'] + }, + description: { + type: String, + maxlength: [2000, 'Should be less than 2001 characters'] + }, + disabilities: { + type: [String], + default: ['none'], + enum: { + values: [ + 'brain', + 'cognitive', + 'hearing', + 'invisible', + 'none', + 'other', + 'physical', + 'private', + 'psychological', + 'spinal-cord', + 'vision' + ], + general: 'Invalid type of disability' + }, + required: [true, 'Is required'] + }, + email: { + type: String, + maxlength: [254, 'Should be less than 255 characters'] + }, + events: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'Event' + } + ], + facebookId: String, + firstName: { + type: String, + maxlength: [24, 'Should be less than 25 characters'], + required: [true, 'Is required'] + }, + gender: { + type: String, + default: 'private', + enum: { + values: ['female', 'male', 'other', 'private', 'transgender'], + general: 'Invalid type of gender' + }, + required: [true, 'Is required'] + }, + googleId: String, + hashedPassword: { + type: String, + maxlength: [256, 'Should be less than 255 characters'] + }, + isAdmin: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isArchived: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isBlocked: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isSubscribed: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + lastName: { + type: String, + maxlength: [36, 'Should be less than 37 characters'], + required: [true, 'Is required'] + }, + language: { + type: String, + default: 'en', + enum: { + values: ['en', 'es'], + general: 'Invalid type of language' + }, + required: [true, 'Is required'] + }, + phone: { + type: String, + maxlength: [50, 'Should be less than 51 characters'] + }, + reviewFieldsAmount: { + type: Number, + default: 0, + required: [true, 'Is required'] + }, + reviewsAmount: { + type: Number, + default: 0, + required: [true, 'Is required'] + }, + showDisabilities: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + showEmail: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + showPhone: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + teams: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + } + ], + username: { + type: String, + maxlength: [67, 'Should be less than 68 characters'] + }, + zip: { + type: String, + maxlength: [32, 'Should be less than 33 characters'] + } + }, + { timestamps: true } +); + +userSchema.index( + { + email: 'text', + firstName: 'text', + lastName: 'text', + username: 'text', + reviewsAmount: 1 + }, + { weights: { email: 5, username: 5 } } +); + +function hashPassword(password) { + bcrypt.genSalt(10, (errorOnSaltGeneration, salt) => { + if (errorOnSaltGeneration) { + return false; + } + + bcrypt.hash( + password, + salt, + null, + (errorOnHashingPassword, hashedPassword) => { + if (errorOnHashingPassword) { + return false; + } + + this.hashedPassword = hashedPassword; + return true; + } + ); + }); +} + +function comparePassword(password) { + return bcrypt.compareSync(password, this.hashedPassword); +} + +userSchema.virtual('password').set(hashPassword); +userSchema.methods.comparePassword = comparePassword; + +module.exports = { + User: mongoose.model('User', userSchema), + userSchema +}; diff --git a/src/models/venue.js b/src/models/venue.js index 9c473f4..e0c475d 100644 --- a/src/models/venue.js +++ b/src/models/venue.js @@ -1,315 +1,315 @@ -const mongoose = require('mongoose'); - -const venueSchema = new mongoose.Schema( - { - //new expanded fields - hasPermanentRamp: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasPortableRamp: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasWideEntrance: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasAccessibleTableHeight: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasAccessibleElevator: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasInteriorRamp: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasSwingOutDoor: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasLargeStall: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasSupportAroundToilet: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasLoweredSinks: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - entranceScore: { - //enum: ['alert', 'caution', 'accessible', 'default'], - //description: 'can only be one of the enum values and is required', - //default: 'default' - type: Number, - default: 0 - }, - entranceGlyphs: { - type: String, - maxlength: [32, 'Should be less than 256 characters'] - }, - interiorScore: { - //enum: ['alert', 'caution', 'accessible', 'default'], - //description: 'can only be one of the enum values and is required', - //: 'default' - type: Number, - default: 0 - }, - interiorGlyphs: { - type: String, - maxlength: [32, 'Should be less than 256 characters'] - }, - restroomScore: { - //enum: ['alert', 'caution', 'accessible', 'default'], - //: 'can only be one of the enum values and is required', - //default: 'default' - type: Number, - default: 0 - }, - restroomGlyphs: { - type: String, - maxlength: [32, 'Should be less than 256 characters'] - }, - mapMarkerScore: { - type: Number, - default: 0 - }, - - //original fields - address: { - type: String, - maxlength: [255, 'Should be less than 256 characters'] - }, - allowsGuideDog: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - - /* - * deprecated 5-star scoring - */ - _bathroomReviews: { - type: Number, - default: 0 - //min: [0, 'Should be more than 1'] - }, - _bathroomScore: { - type: Number - //max: [4, 'Should be less than 5'], - //min: [1, 'Should be more than 0'] - }, - _entryReviews: { - type: Number, - default: 0 - //min: [0, 'Should be more than -1'] - }, - _entryScore: { - type: Number - //max: [9, 'Should be less than 10'], - //min: [1, 'Should be more than 0'] - }, - _isScoreConverted: { - type: Boolean, - default: false - }, - - hasParking: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasSecondEntry: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasWellLit: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isQuiet: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - isSpacious: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - location: { - type: { - type: String, - default: 'Point' - }, - coordinates: [Number] - }, - name: { - type: String, - maxlength: [255, 'Should be less than 256 characters'] - }, - photos: [ - { - type: mongoose.Schema.ObjectId, - ref: 'Photo' - } - ], - placeId: { - type: String, - maxlength: [255, 'Should be less than 256 characters'], - required: [true, 'Is required'] - }, - reviews: [ - { - type: mongoose.Schema.ObjectId, - ref: 'Review' - } - ], - steps: { - zero: { - type: Number, - default: 0 - }, - one: { - type: Number, - default: 0 - }, - two: { - type: Number, - default: 0 - }, - moreThanTwo: { - type: Number, - default: 0 - } - }, - types: [ - { - type: String, - maxlength: [50, 'Should be less than 51 characters'] - } - ] - }, - { timestamps: true } -); - -venueSchema.index({ location: '2dsphere', placeId: 1 }); - -venueSchema.virtual('coordinates').get(function() { - return { - lat: this.location.coordinates[1], - lng: this.location.coordinates[0] - }; -}); - -venueSchema.virtual('photo').get(function() { - return undefined; -}); - -module.exports = { - Venue: mongoose.model('Venue', venueSchema), - venueSchema -}; +const mongoose = require('mongoose'); + +const venueSchema = new mongoose.Schema( + { + //new expanded fields + hasPermanentRamp: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasPortableRamp: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasWideEntrance: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasAccessibleTableHeight: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasAccessibleElevator: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasInteriorRamp: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasSwingOutDoor: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasLargeStall: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasSupportAroundToilet: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasLoweredSinks: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + entranceScore: { + //enum: ['alert', 'caution', 'accessible', 'default'], + //description: 'can only be one of the enum values and is required', + //default: 'default' + type: Number, + default: 0 + }, + entranceGlyphs: { + type: String, + maxlength: [32, 'Should be less than 256 characters'] + }, + interiorScore: { + //enum: ['alert', 'caution', 'accessible', 'default'], + //description: 'can only be one of the enum values and is required', + //: 'default' + type: Number, + default: 0 + }, + interiorGlyphs: { + type: String, + maxlength: [32, 'Should be less than 256 characters'] + }, + restroomScore: { + //enum: ['alert', 'caution', 'accessible', 'default'], + //: 'can only be one of the enum values and is required', + //default: 'default' + type: Number, + default: 0 + }, + restroomGlyphs: { + type: String, + maxlength: [32, 'Should be less than 256 characters'] + }, + mapMarkerScore: { + type: Number, + default: 0 + }, + + //original fields + address: { + type: String, + maxlength: [255, 'Should be less than 256 characters'] + }, + allowsGuideDog: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + + /* + * deprecated 5-star scoring + */ + _bathroomReviews: { + type: Number, + default: 0 + //min: [0, 'Should be more than 1'] + }, + _bathroomScore: { + type: Number + //max: [4, 'Should be less than 5'], + //min: [1, 'Should be more than 0'] + }, + _entryReviews: { + type: Number, + default: 0 + //min: [0, 'Should be more than -1'] + }, + _entryScore: { + type: Number + //max: [9, 'Should be less than 10'], + //min: [1, 'Should be more than 0'] + }, + _isScoreConverted: { + type: Boolean, + default: false + }, + + hasParking: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasSecondEntry: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasWellLit: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + isArchived: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isQuiet: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + isSpacious: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + location: { + type: { + type: String, + default: 'Point' + }, + coordinates: [Number] + }, + name: { + type: String, + maxlength: [255, 'Should be less than 256 characters'] + }, + photos: [ + { + type: mongoose.Schema.ObjectId, + ref: 'Photo' + } + ], + placeId: { + type: String, + maxlength: [255, 'Should be less than 256 characters'], + required: [true, 'Is required'] + }, + reviews: [ + { + type: mongoose.Schema.ObjectId, + ref: 'Review' + } + ], + steps: { + zero: { + type: Number, + default: 0 + }, + one: { + type: Number, + default: 0 + }, + two: { + type: Number, + default: 0 + }, + moreThanTwo: { + type: Number, + default: 0 + } + }, + types: [ + { + type: String, + maxlength: [50, 'Should be less than 51 characters'] + } + ] + }, + { timestamps: true } +); + +venueSchema.index({ location: '2dsphere', placeId: 1 }); + +venueSchema.virtual('coordinates').get(function () { + return { + lat: this.location.coordinates[1], + lng: this.location.coordinates[0] + }; +}); + +venueSchema.virtual('photo').get(function () { + return undefined; +}); + +module.exports = { + Venue: mongoose.model('Venue', venueSchema), + venueSchema +}; diff --git a/src/routes/auth/activate-account.js b/src/routes/auth/activate-account.js index b78caf7..e5a0655 100644 --- a/src/routes/auth/activate-account.js +++ b/src/routes/auth/activate-account.js @@ -1,139 +1,139 @@ -const crypto = require('crypto'); - -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { ActivationTicket } = require('../../models/activation-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - const key = req.params.key; - - let activationTicket; - try { - activationTicket = await ActivationTicket.findOne({ key }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Activation ticket not found' }); - } - - console.log( - `Activation ticket with key ${key} failed to be found at activate-account.` - ); - return next(err); - } - - if (!activationTicket) { - return res.status(404).json({ general: 'Activation ticket not found' }); - } - - let expiresAt = moment(activationTicket.expiresAt).utc(); - const now = moment.utc(); - if (expiresAt.isBefore(now)) { - try { - await activationTicket.remove(); - } catch (err) { - console.log( - `Activation ticket with key ${ - activationTicket.key - } failed to be deleted at activate-account.` - ); - return next(err); - } - - return res.status(400).json({ general: 'Activation ticket expired' }); - } - - const userData = Object.assign({}, activationTicket.userData, { - email: activationTicket.email - }); - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - $or: [{ email: userData.email }, { username: userData.username }], - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at activate-account.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - for (const user of repeatedUsers) { - if (user.email === userData.email) { - return res.status(400).json({ email: 'Is already taken' }); - } - - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at activate-account.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - } - - let user; - try { - user = await User.create(userData); - } catch (err) { - console.log( - `User failed to be created at activate-account.\nData: ${JSON.stringify( - userData - )}` - ); - return next(err); - } - - const today = moment.utc(); - expiresAt = today.add(14, 'days').toDate(); - const refreshTokenData = { - expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id - }; - - try { - await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token failed to be created at activate-account.\nData: ${JSON.stringify( - refreshTokenData - )}` - ); - return next(err); - } - - try { - await activationTicket.remove(); - } catch (err) { - console.log( - `Activation ticket with key ${ - activationTicket.key - } failed to be deleted at activate-account.` - ); - return next(err); - } - - return res.redirect(`${process.env.APP_URL}/sign-in`); -}; +const crypto = require('crypto'); + +const moment = require('moment'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +const { ActivationTicket } = require('../../models/activation-ticket'); +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + const key = req.params.key; + + let activationTicket; + try { + activationTicket = await ActivationTicket.findOne({ key }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Activation ticket not found' }); + } + + console.log( + `Activation ticket with key ${key} failed to be found at activate-account.` + ); + return next(err); + } + + if (!activationTicket) { + return res.status(404).json({ general: 'Activation ticket not found' }); + } + + let expiresAt = moment(activationTicket.expiresAt).utc(); + const now = moment.utc(); + if (expiresAt.isBefore(now)) { + try { + await activationTicket.remove(); + } catch (err) { + console.log( + `Activation ticket with key ${ + activationTicket.key + } failed to be deleted at activate-account.` + ); + return next(err); + } + + return res.status(400).json({ general: 'Activation ticket expired' }); + } + + const userData = Object.assign({}, activationTicket.userData, { + email: activationTicket.email + }); + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + $or: [{ email: userData.email }, { username: userData.username }], + isArchived: false + }); + } catch (err) { + console.log('Users failed to be found at activate-account.'); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + for (const user of repeatedUsers) { + if (user.email === userData.email) { + return res.status(400).json({ email: 'Is already taken' }); + } + + let repeatedUser; + do { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}`; + + try { + repeatedUser = await User.findOne({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${ + userData.username + } failed to be found at activate-account.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === userData.username); + } + } + + let user; + try { + user = await User.create(userData); + } catch (err) { + console.log( + `User failed to be created at activate-account.\nData: ${JSON.stringify( + userData + )}` + ); + return next(err); + } + + const today = moment.utc(); + expiresAt = today.add(14, 'days').toDate(); + const refreshTokenData = { + expiresAt, + key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, + userId: user.id + }; + + try { + await RefreshToken.create(refreshTokenData); + } catch (err) { + console.log( + `Refresh token failed to be created at activate-account.\nData: ${JSON.stringify( + refreshTokenData + )}` + ); + return next(err); + } + + try { + await activationTicket.remove(); + } catch (err) { + console.log( + `Activation ticket with key ${ + activationTicket.key + } failed to be deleted at activate-account.` + ); + return next(err); + } + + return res.redirect(`${process.env.APP_URL}/sign-in`); +}; diff --git a/src/routes/auth/facebook-sign-in.js b/src/routes/auth/facebook-sign-in.js index bc68c5e..d5477ac 100644 --- a/src/routes/auth/facebook-sign-in.js +++ b/src/routes/auth/facebook-sign-in.js @@ -1,200 +1,201 @@ -const crypto = require('crypto'); - -const axios = require('axios'); -const jwt = require('jsonwebtoken'); -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateFacebookSignIn } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateFacebookSignIn(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const code = req.body.code; - - const getTokenUrl = 'https://graph.facebook.com/v2.10/oauth/access_token'; - const getTokenParams = { - code, - client_id: process.env.FACEBOOK_CLIENT_ID, - client_secret: process.env.FACEBOOK_CLIENT_SECRET, - redirect_uri: `${process.env.APP_URL}/auth/facebook` - }; - let getTokenResponse; - try { - getTokenResponse = await axios.get(getTokenUrl, { params: getTokenParams }); - } catch (err) { - return res.status(400).json({ general: 'Invalid code' }); - } - - const facebookToken = getTokenResponse.data.access_token; - - const getProfileUrl = - 'https://graph.facebook.com/v2.10/me?fields=id,email,first_name,last_name,locale'; - const getProfileOptions = { - params: { - access_token: facebookToken - } - }; - let getProfileResponse; - try { - getProfileResponse = await axios.get(getProfileUrl, getProfileOptions); - } catch (err) { - console.log('Profile data failed to be found at facebook-sign-in.'); - return next(err); - } - - const email = getProfileResponse.data.email - ? getProfileResponse.data.email - : ''; - const facebookId = getProfileResponse.data.id; - let user; - try { - user = await User.findOne({ - $or: [{ email }, { facebookId }], - isArchived: false - }); - } catch (err) { - console.log( - `User with facebookId ${facebookId} and email ${email} failed to be found at facebook-sign-in.` - ); - return next(err); - } - - let accessToken; - let refreshToken; - - if (!user) { - console.log(getProfileResponse.data); - const userData = { - email: getProfileResponse.data.email ? getProfileResponse.data.email : '', - facebookId: getProfileResponse.data.id, - firstName: getProfileResponse.data.first_name, - lastName: getProfileResponse.data.last_name - }; - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}`; - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at facebook-sign-in.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at facebook-sign-in.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - - const getPictureUrl = `https://graph.facebook.com/v2.10/${ - userData.facebookId - }/picture`; - const getPictureOptions = { - params: { - access_token: accessToken, - redirect: false, - type: 'large' - } - }; - let getPictureResponse; - try { - getPictureResponse = await axios.get(getPictureUrl, getPictureOptions); - } catch (err) { - console.log('User picture failed to be found at facebook-sign-in.'); - return next(err); - } - - const isSilhouette = getPictureResponse.data.data.is_silhouette; - if (!isSilhouette) { - userData.avatar = getPictureResponse.data.data.url; - } - - try { - user = await User.create(userData); - } catch (err) { - console.log( - `User failed to be created at facebook-sign-in.\nData: ${JSON.stringify( - userData - )}` - ); - return next(err); - } - - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const refreshTokenData = { - expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id - }; - - try { - refreshToken = await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token failed to be created at facebook-sign-in.\nData: ${JSON.stringify( - refreshTokenData - )}` - ); - return next(err); - } - } else { - const userId = user.id; - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; - - try { - refreshToken = await RefreshToken.findOneAndUpdate( - { userId }, - { expiresAt, key, userId }, - { new: true, setDefaultsOnInsert: true, upsert: true } - ); - } catch (err) { - console.log( - `Refresh Token for userId ${userId} failed to be created or updated at facebook-sign-in.` - ); - return next(err); - } - } - - const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { - expiresIn: 3600 - }); - refreshToken = refreshToken.key; - - return res.status(200).json({ token, refreshToken }); -}; +const crypto = require('crypto'); + +const axios = require('axios'); +const jwt = require('jsonwebtoken'); +const moment = require('moment'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +const { validateFacebookSignIn } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateFacebookSignIn(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const code = req.body.code; + + const getTokenUrl = 'https://graph.facebook.com/v2.10/oauth/access_token'; + const getTokenParams = { + code, + client_id: process.env.FACEBOOK_CLIENT_ID, + client_secret: process.env.FACEBOOK_CLIENT_SECRET, + redirect_uri: `${process.env.APP_URL}/auth/facebook` + }; + let getTokenResponse; + try { + getTokenResponse = await axios.get(getTokenUrl, { params: getTokenParams }); + } catch (err) { + console.err(err); + return res.status(400).json({ general: 'Invalid code' }); + } + + const facebookToken = getTokenResponse.data.access_token; + + const getProfileUrl = + 'https://graph.facebook.com/v2.10/me?fields=id,email,first_name,last_name,locale'; + const getProfileOptions = { + params: { + access_token: facebookToken + } + }; + let getProfileResponse; + try { + getProfileResponse = await axios.get(getProfileUrl, getProfileOptions); + } catch (err) { + console.log('Profile data failed to be found at facebook-sign-in.'); + return next(err); + } + + const email = getProfileResponse.data.email + ? getProfileResponse.data.email + : ''; + const facebookId = getProfileResponse.data.id; + let user; + try { + user = await User.findOne({ + $or: [{ email }, { facebookId }], + isArchived: false + }); + } catch (err) { + console.log( + `User with facebookId ${facebookId} and email ${email} failed to be found at facebook-sign-in.` + ); + return next(err); + } + + let accessToken; + let refreshToken; + + if (!user) { + console.log(getProfileResponse.data); + const userData = { + email: getProfileResponse.data.email ? getProfileResponse.data.email : '', + facebookId: getProfileResponse.data.id, + firstName: getProfileResponse.data.first_name, + lastName: getProfileResponse.data.last_name + }; + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}`; + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log('Users failed to be found at facebook-sign-in.'); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + let repeatedUser; + do { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}`; + + try { + repeatedUser = await User.findOne({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${ + userData.username + } failed to be found at facebook-sign-in.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === userData.username); + } + + const getPictureUrl = `https://graph.facebook.com/v2.10/${ + userData.facebookId + }/picture`; + const getPictureOptions = { + params: { + access_token: accessToken, + redirect: false, + type: 'large' + } + }; + let getPictureResponse; + try { + getPictureResponse = await axios.get(getPictureUrl, getPictureOptions); + } catch (err) { + console.log('User picture failed to be found at facebook-sign-in.'); + return next(err); + } + + const isSilhouette = getPictureResponse.data.data.is_silhouette; + if (!isSilhouette) { + userData.avatar = getPictureResponse.data.data.url; + } + + try { + user = await User.create(userData); + } catch (err) { + console.log( + `User failed to be created at facebook-sign-in.\nData: ${JSON.stringify( + userData + )}` + ); + return next(err); + } + + const today = moment.utc(); + const expiresAt = today.add(14, 'days').toDate(); + const refreshTokenData = { + expiresAt, + key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, + userId: user.id + }; + + try { + refreshToken = await RefreshToken.create(refreshTokenData); + } catch (err) { + console.log( + `Refresh token failed to be created at facebook-sign-in.\nData: ${JSON.stringify( + refreshTokenData + )}` + ); + return next(err); + } + } else { + const userId = user.id; + const today = moment.utc(); + const expiresAt = today.add(14, 'days').toDate(); + const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; + + try { + refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + } catch (err) { + console.log( + `Refresh Token for userId ${userId} failed to be created or updated at facebook-sign-in.` + ); + return next(err); + } + } + + const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { + expiresIn: 3600 + }); + refreshToken = refreshToken.key; + + return res.status(200).json({ token, refreshToken }); +}; diff --git a/src/routes/auth/forgotten-password.js b/src/routes/auth/forgotten-password.js index ed3039f..e1e18f7 100644 --- a/src/routes/auth/forgotten-password.js +++ b/src/routes/auth/forgotten-password.js @@ -1,88 +1,88 @@ -const crypto = require('crypto'); - -const moment = require('moment'); - -const { PasswordTicket } = require('../../models/password-ticket'); -const { sendEmail } = require('../../helpers'); -const { User } = require('../../models/user'); - -const { validateForgottenPassword } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateForgottenPassword(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const email = req.body.email; - - let user; - try { - user = await User.findOne({ email, isArchived: false }); - } catch (err) { - console.log( - `User with email ${email} failed to be found at forgotten-password.` - ); - return next(err); - } - - if (!user) { - return res.status(200).json({ general: 'Success' }); - } - - try { - await PasswordTicket.remove({ email }); - } catch (err) { - console.log( - `Password ticket with email ${email} failed to be removed at forgotten-password.` - ); - return next(err); - } - - const today = moment.utc(); - const expiresAt = today.add(1, 'days').toDate(); - const key = `${crypto - .randomBytes(31) - .toString('hex')}${new Date().getTime().toString()}`; - - let passwordTicket; - try { - passwordTicket = await PasswordTicket.create({ email, expiresAt, key }); - } catch (err) { - console.log( - `Password ticket failed to be created at forgotten-password.\nData: ${JSON.stringify( - { email, expiresAt, key } - )}` - ); - return next(err); - } - - const htmlContent = ` -
To reset your password use the link below:
-Stay awesome.
- `; - const receiversEmails = [passwordTicket.email]; - const subject = 'Reset Password'; - const textContent = ` - Hi from AXS Map! - To reset your password use the link below: - ${process.env.APP_URL}/reset-password?key=${passwordTicket.key} - Stay awesome. - `; - - sendEmail({ - receiversEmails, - subject, - htmlContent, - textContent - }); - - return res.status(200).json({ general: 'Success' }); -}; +const crypto = require('crypto'); + +const moment = require('moment'); + +const { PasswordTicket } = require('../../models/password-ticket'); +const { sendEmail } = require('../../helpers'); +const { User } = require('../../models/user'); + +const { validateForgottenPassword } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateForgottenPassword(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const email = req.body.email; + + let user; + try { + user = await User.findOne({ email, isArchived: false }); + } catch (err) { + console.log( + `User with email ${email} failed to be found at forgotten-password.` + ); + return next(err); + } + + if (!user) { + return res.status(200).json({ general: 'Success' }); + } + + try { + await PasswordTicket.remove({ email }); + } catch (err) { + console.log( + `Password ticket with email ${email} failed to be removed at forgotten-password.` + ); + return next(err); + } + + const today = moment.utc(); + const expiresAt = today.add(1, 'days').toDate(); + const key = `${crypto + .randomBytes(31) + .toString('hex')}${new Date().getTime().toString()}`; + + let passwordTicket; + try { + passwordTicket = await PasswordTicket.create({ email, expiresAt, key }); + } catch (err) { + console.log( + `Password ticket failed to be created at forgotten-password.\nData: ${JSON.stringify( + { email, expiresAt, key } + )}` + ); + return next(err); + } + + const htmlContent = ` +To reset your password use the link below:
+Stay awesome.
+ `; + const receiversEmails = [passwordTicket.email]; + const subject = 'Reset Password'; + const textContent = ` + Hi from AXS Map! + To reset your password use the link below: + ${process.env.APP_URL}/reset-password?key=${passwordTicket.key} + Stay awesome. + `; + + sendEmail({ + receiversEmails, + subject, + htmlContent, + textContent + }); + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/auth/generate-token.js b/src/routes/auth/generate-token.js index ba1016f..689e2d2 100644 --- a/src/routes/auth/generate-token.js +++ b/src/routes/auth/generate-token.js @@ -1,55 +1,55 @@ -const jwt = require('jsonwebtoken'); -const moment = require('moment'); - -const { RefreshToken } = require('../../models/refresh-token'); - -const { validateGenerateToken } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateGenerateToken(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const key = req.body.key; - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ key }); - } catch (err) { - console.log( - `Refresh Token with key ${key} failed to be found at generate-token.` - ); - return next(err); - } - - if (!refreshToken) { - return res.status(404).json({ general: 'Refresh Token not found' }); - } - - const expiresAt = moment(refreshToken.expiresAt).utc(); - const today = moment.utc(); - if (expiresAt.isBefore(today)) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh Token with key ${ - refreshToken.key - } failed to be removed at generate-token.` - ); - return next(err); - } - - return res.status(401).json({ general: 'Refresh Token expired' }); - } - - const token = jwt.sign( - { userId: refreshToken.userId }, - process.env.JWT_SECRET, - { - expiresIn: 3600 - } - ); - return res.status(200).json({ token }); -}; +const jwt = require('jsonwebtoken'); +const moment = require('moment'); + +const { RefreshToken } = require('../../models/refresh-token'); + +const { validateGenerateToken } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateGenerateToken(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const key = req.body.key; + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ key }); + } catch (err) { + console.log( + `Refresh Token with key ${key} failed to be found at generate-token.` + ); + return next(err); + } + + if (!refreshToken) { + return res.status(404).json({ general: 'Refresh Token not found' }); + } + + const expiresAt = moment(refreshToken.expiresAt).utc(); + const today = moment.utc(); + if (expiresAt.isBefore(today)) { + try { + await refreshToken.remove(); + } catch (err) { + console.log( + `Refresh Token with key ${ + refreshToken.key + } failed to be removed at generate-token.` + ); + return next(err); + } + + return res.status(401).json({ general: 'Refresh Token expired' }); + } + + const token = jwt.sign( + { userId: refreshToken.userId }, + process.env.JWT_SECRET, + { + expiresIn: 3600 + } + ); + return res.status(200).json({ token }); +}; diff --git a/src/routes/auth/google-sign-in.js b/src/routes/auth/google-sign-in.js index 6031188..14c2a84 100644 --- a/src/routes/auth/google-sign-in.js +++ b/src/routes/auth/google-sign-in.js @@ -1,188 +1,189 @@ -const crypto = require('crypto'); -const querystring = require('querystring'); - -const axios = require('axios'); -const GoogleAuth = require('google-auth-library'); -const jwt = require('jsonwebtoken'); -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateGoogleSignIn } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateGoogleSignIn(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const code = req.body.code; - - const getTokenUrl = 'https://www.googleapis.com/oauth2/v4/token'; - const getTokenParams = { - code, - client_id: process.env.GOOGLE_CLIENT_ID, - client_secret: process.env.GOOGLE_CLIENT_SECRET, - redirect_uri: `${process.env.APP_URL}/auth/google`, - grant_type: 'authorization_code' - }; - let getTokenResponse; - try { - getTokenResponse = await axios.post( - getTokenUrl, - querystring.stringify(getTokenParams) - ); - } catch (err) { - return res.status(400).json({ general: 'Invalid code' }); - } - - const auth = new GoogleAuth(); - const client = new auth.OAuth2(process.env.GOOGLE_CLIENT_ID, '', ''); - const idToken = getTokenResponse.data.id_token; - client.verifyIdToken( - idToken, - process.env.GOOGLE_CLIENT_ID, - async (err, login) => { - if (err) { - return res.status(400).json({ general: 'Invalid token id' }); - } - - const payload = login.getPayload(); - - const email = payload.email; - const googleId = payload.sub; - let user; - try { - user = await User.findOne({ - $or: [{ email }, { googleId }], - isArchived: false - }); - } catch (err) { - console.log( - `User with googleId ${googleId} and email ${email} failed to be found at google-sign-in.` - ); - return next(err); - } - - let refreshToken; - - if (!user) { - const userData = { - email: payload.email, - googleId: payload.sub, - firstName: payload.given_name, - lastName: payload.family_name - }; - - if (payload.locale === 'en') { - userData.language = 'en'; - } else if (payload.locale === 'es') { - userData.language = 'es'; - } - - if (payload.picture) { - userData.avatar = payload.picture; - } - - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}`; - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at google-sign-in.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at google-sign-in.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - - try { - user = await User.create(userData); - } catch (err) { - console.log( - `User failed to be created at google-sign-in.\nData: ${JSON.stringify( - userData - )}` - ); - return next(err); - } - - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const refreshTokenData = { - expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id - }; - - try { - refreshToken = await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token failed to be created at google-sign-in.\nData: ${JSON.stringify( - refreshTokenData - )}` - ); - return next(err); - } - } else { - const userId = user.id; - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; - - try { - refreshToken = await RefreshToken.findOneAndUpdate( - { userId }, - { expiresAt, key, userId }, - { new: true, setDefaultsOnInsert: true, upsert: true } - ); - } catch (err) { - console.log( - `Refresh Token for userId ${userId} failed to be created or updated at google-sign-in.` - ); - return next(err); - } - } - - const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { - expiresIn: 3600 - }); - refreshToken = refreshToken.key; - - return res.status(200).json({ token, refreshToken }); - } - ); -}; +const crypto = require('crypto'); +const querystring = require('querystring'); + +const axios = require('axios'); +const GoogleAuth = require('google-auth-library'); +const jwt = require('jsonwebtoken'); +const moment = require('moment'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +const { validateGoogleSignIn } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateGoogleSignIn(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const code = req.body.code; + + const getTokenUrl = 'https://www.googleapis.com/oauth2/v4/token'; + const getTokenParams = { + code, + client_id: process.env.GOOGLE_CLIENT_ID, + client_secret: process.env.GOOGLE_CLIENT_SECRET, + redirect_uri: `${process.env.APP_URL}/auth/google`, + grant_type: 'authorization_code' + }; + let getTokenResponse; + try { + getTokenResponse = await axios.post( + getTokenUrl, + querystring.stringify(getTokenParams) + ); + } catch (err) { + console.error(err); + return res.status(400).json({ general: 'Invalid code' }); + } + + const auth = new GoogleAuth(); + const client = new auth.OAuth2(process.env.GOOGLE_CLIENT_ID, '', ''); + const idToken = getTokenResponse.data.id_token; + client.verifyIdToken( + idToken, + process.env.GOOGLE_CLIENT_ID, + async (err, login) => { + if (err) { + return res.status(400).json({ general: 'Invalid token id' }); + } + + const payload = login.getPayload(); + + const email = payload.email; + const googleId = payload.sub; + let user; + try { + user = await User.findOne({ + $or: [{ email }, { googleId }], + isArchived: false + }); + } catch (err) { + console.log( + `User with googleId ${googleId} and email ${email} failed to be found at google-sign-in.` + ); + return next(err); + } + + let refreshToken; + + if (!user) { + const userData = { + email: payload.email, + googleId: payload.sub, + firstName: payload.given_name, + lastName: payload.family_name + }; + + if (payload.locale === 'en') { + userData.language = 'en'; + } else if (payload.locale === 'es') { + userData.language = 'es'; + } + + if (payload.picture) { + userData.avatar = payload.picture; + } + + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}`; + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log('Users failed to be found at google-sign-in.'); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + let repeatedUser; + do { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}`; + + try { + repeatedUser = await User.findOne({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${ + userData.username + } failed to be found at google-sign-in.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === userData.username); + } + + try { + user = await User.create(userData); + } catch (err) { + console.log( + `User failed to be created at google-sign-in.\nData: ${JSON.stringify( + userData + )}` + ); + return next(err); + } + + const today = moment.utc(); + const expiresAt = today.add(14, 'days').toDate(); + const refreshTokenData = { + expiresAt, + key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, + userId: user.id + }; + + try { + refreshToken = await RefreshToken.create(refreshTokenData); + } catch (err) { + console.log( + `Refresh token failed to be created at google-sign-in.\nData: ${JSON.stringify( + refreshTokenData + )}` + ); + return next(err); + } + } else { + const userId = user.id; + const today = moment.utc(); + const expiresAt = today.add(14, 'days').toDate(); + const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; + + try { + refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + } catch (err) { + console.log( + `Refresh Token for userId ${userId} failed to be created or updated at google-sign-in.` + ); + return next(err); + } + } + + const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { + expiresIn: 3600 + }); + refreshToken = refreshToken.key; + + return res.status(200).json({ token, refreshToken }); + } + ); +}; diff --git a/src/routes/auth/index.js b/src/routes/auth/index.js index d1cb782..431d0c8 100644 --- a/src/routes/auth/index.js +++ b/src/routes/auth/index.js @@ -1,27 +1,27 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const activateAccount = require('./activate-account'); -const facebookSignIn = require('./facebook-sign-in'); -const forgottenPassword = require('./forgotten-password'); -const generateToken = require('./generate-token'); -const googleSignIn = require('./google-sign-in'); -const resetPassword = require('./reset-password'); -const signIn = require('./sign-in'); -const signOut = require('./sign-out'); -const signUp = require('./sign-up'); - -const router = new express.Router(); - -router.get('/activate-account/:key', activateAccount); -router.post('/facebook', facebookSignIn); -router.post('/forgotten-password', forgottenPassword); -router.post('/google', googleSignIn); -router.put('/reset-password', resetPassword); -router.post('/sign-in', signIn); -router.delete('/sign-out', isAuthenticated({ isOptional: false }), signOut); -router.post('/sign-up', signUp); -router.post('/token', generateToken); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const activateAccount = require('./activate-account'); +const facebookSignIn = require('./facebook-sign-in'); +const forgottenPassword = require('./forgotten-password'); +const generateToken = require('./generate-token'); +const googleSignIn = require('./google-sign-in'); +const resetPassword = require('./reset-password'); +const signIn = require('./sign-in'); +const signOut = require('./sign-out'); +const signUp = require('./sign-up'); + +const router = new express.Router(); + +router.get('/activate-account/:key', activateAccount); +router.post('/facebook', facebookSignIn); +router.post('/forgotten-password', forgottenPassword); +router.post('/google', googleSignIn); +router.put('/reset-password', resetPassword); +router.post('/sign-in', signIn); +router.delete('/sign-out', isAuthenticated({ isOptional: false }), signOut); +router.post('/sign-up', signUp); +router.post('/token', generateToken); + +module.exports = router; diff --git a/src/routes/auth/reset-password.js b/src/routes/auth/reset-password.js index 5e69206..51f6a90 100644 --- a/src/routes/auth/reset-password.js +++ b/src/routes/auth/reset-password.js @@ -1,133 +1,133 @@ -const moment = require('moment'); - -const { PasswordTicket } = require('../../models/password-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateResetPassword } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateResetPassword(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const key = req.body.key; - const password = req.body.password; - - let passwordTicket; - try { - passwordTicket = await PasswordTicket.findOne({ key }); - } catch (err) { - console.log( - `Password ticket with key ${key} failed to be found at reset-password.` - ); - return next(err); - } - - if (!passwordTicket) { - return res.status(404).json({ general: 'Password Ticket not found' }); - } - - const expiresAt = moment(passwordTicket.expiresAt).utc(); - const today = moment.utc(); - if (expiresAt.isBefore(today)) { - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password Ticket with key ${ - passwordTicket.key - } failed to be removed at reset-password.` - ); - return next(err); - } - - return res.status(400).json({ general: 'Password Ticket expired' }); - } - - let user; - try { - user = await User.findOne({ - email: passwordTicket.email, - isArchived: false - }); - } catch (err) { - console.log( - `User with email ${ - passwordTicket.email - } failed to be found at reset-password.` - ); - return next(err); - } - - if (!user) { - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password Ticket with key ${ - passwordTicket.key - } failed to be removed at reset-password.` - ); - return next(err); - } - - return res.status(400).json({ general: 'User not found' }); - } - - const passwordMatches = user.comparePassword(password); - if (passwordMatches) { - return res.status(400).json({ password: 'Is already used' }); - } - - user.password = password; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User with email ${user.email} failed to be updated at reset-password.` - ); - return next(err); - } - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ userId: user.id }); - } catch (err) { - console.log( - `Refresh token with userId ${ - user.id - } failed to be found at reset-password.` - ); - return next(err); - } - - if (refreshToken) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh Token with userId ${ - refreshToken.userId - } failed to be removed at reset-password.` - ); - return next(err); - } - } - - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password Ticket with key ${ - passwordTicket.key - } failed to be removed at reset-password.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { PasswordTicket } = require('../../models/password-ticket'); +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +const { validateResetPassword } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateResetPassword(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const key = req.body.key; + const password = req.body.password; + + let passwordTicket; + try { + passwordTicket = await PasswordTicket.findOne({ key }); + } catch (err) { + console.log( + `Password ticket with key ${key} failed to be found at reset-password.` + ); + return next(err); + } + + if (!passwordTicket) { + return res.status(404).json({ general: 'Password Ticket not found' }); + } + + const expiresAt = moment(passwordTicket.expiresAt).utc(); + const today = moment.utc(); + if (expiresAt.isBefore(today)) { + try { + await passwordTicket.remove(); + } catch (err) { + console.log( + `Password Ticket with key ${ + passwordTicket.key + } failed to be removed at reset-password.` + ); + return next(err); + } + + return res.status(400).json({ general: 'Password Ticket expired' }); + } + + let user; + try { + user = await User.findOne({ + email: passwordTicket.email, + isArchived: false + }); + } catch (err) { + console.log( + `User with email ${ + passwordTicket.email + } failed to be found at reset-password.` + ); + return next(err); + } + + if (!user) { + try { + await passwordTicket.remove(); + } catch (err) { + console.log( + `Password Ticket with key ${ + passwordTicket.key + } failed to be removed at reset-password.` + ); + return next(err); + } + + return res.status(400).json({ general: 'User not found' }); + } + + const passwordMatches = user.comparePassword(password); + if (passwordMatches) { + return res.status(400).json({ password: 'Is already used' }); + } + + user.password = password; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User with email ${user.email} failed to be updated at reset-password.` + ); + return next(err); + } + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ userId: user.id }); + } catch (err) { + console.log( + `Refresh token with userId ${ + user.id + } failed to be found at reset-password.` + ); + return next(err); + } + + if (refreshToken) { + try { + await refreshToken.remove(); + } catch (err) { + console.log( + `Refresh Token with userId ${ + refreshToken.userId + } failed to be removed at reset-password.` + ); + return next(err); + } + } + + try { + await passwordTicket.remove(); + } catch (err) { + console.log( + `Password Ticket with key ${ + passwordTicket.key + } failed to be removed at reset-password.` + ); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/auth/sign-in.js b/src/routes/auth/sign-in.js index f0ac99d..3582e2f 100644 --- a/src/routes/auth/sign-in.js +++ b/src/routes/auth/sign-in.js @@ -1,69 +1,70 @@ -const crypto = require('crypto'); - -const jwt = require('jsonwebtoken'); -const moment = require('moment'); - -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateSignIn } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateSignIn(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const email = req.body.email; - const password = req.body.password; - - let user; - try { - user = await User.findOne({ email, isArchived: false }); - } catch (err) { - console.log(`User with email ${email} failed to be found at sign-in.`); - return next(err); - } - - if (!user) { - return res.status(400).json({ general: 'Email or password incorrect' }); - } - - if (user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - if (!user.hashedPassword) { - return res.status(400).json({ general: 'Email or password incorrect' }); - } - - const passwordMatches = user.comparePassword(password); - - if (!passwordMatches) { - return res.status(400).json({ general: 'Email or password incorrect' }); - } - - const userId = user.id; - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; - - let refreshToken; - try { - refreshToken = await RefreshToken.findOneAndUpdate( - { userId }, - { expiresAt, key, userId }, - { new: true, setDefaultsOnInsert: true, upsert: true } - ); - } catch (err) { - console.log( - `Refresh Token for userId ${userId} failed to be created or updated at sign-in.` - ); - return next(err); - } - - const token = jwt.sign({ userId }, process.env.JWT_SECRET, { - expiresIn: 36000 - }); - return res.status(200).json({ refreshToken: refreshToken.key, token }); -}; +const crypto = require("crypto"); + +const jwt = require("jsonwebtoken"); +const moment = require("moment"); + +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); + +const { validateSignIn } = require("./validations"); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateSignIn(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const email = req.body.email; + const password = req.body.password; + + let user; + try { + user = await User.findOne({ email, isArchived: false }); + console.log("User", user); + } catch (err) { + console.log(`User with email ${email} failed to be found at sign-in.`); + return next(err); + } + + if (!user) { + return res.status(400).json({ general: "Email or password incorrect" }); + } + + if (user.isBlocked) { + return res.status(423).json({ general: "You are blocked" }); + } + + if (!user.hashedPassword) { + return res.status(400).json({ general: "Email or password incorrect" }); + } + + const passwordMatches = user.comparePassword(password); + + if (!passwordMatches) { + return res.status(400).json({ general: "Email or password incorrect" }); + } + + const userId = user.id; + const today = moment.utc(); + const expiresAt = today.add(14, "days").toDate(); + const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; + + let refreshToken; + try { + refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + } catch (err) { + console.log( + `Refresh Token for userId ${userId} failed to be created or updated at sign-in.` + ); + return next(err); + } + + const token = jwt.sign({ userId }, process.env.JWT_SECRET, { + expiresIn: 36000, + }); + return res.status(200).json({ refreshToken: refreshToken.key, token }); +}; diff --git a/src/routes/auth/sign-out.js b/src/routes/auth/sign-out.js index 075ef8d..6810f6b 100644 --- a/src/routes/auth/sign-out.js +++ b/src/routes/auth/sign-out.js @@ -1,34 +1,34 @@ -const { RefreshToken } = require('../../models/refresh-token'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ userId: req.user.id }); - } catch (err) { - console.log( - `Refresh token with userId ${req.user.id} failed to be found at sign-out.` - ); - return next(err); - } - - if (!refreshToken) { - return res.status(204).json({ general: 'Success' }); - } - - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh token with userId ${ - req.user.id - } failed to be deleted at sign-out.` - ); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const { RefreshToken } = require('../../models/refresh-token'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ userId: req.user.id }); + } catch (err) { + console.log( + `Refresh token with userId ${req.user.id} failed to be found at sign-out.` + ); + return next(err); + } + + if (!refreshToken) { + return res.status(204).json({ general: 'Success' }); + } + + try { + await refreshToken.remove(); + } catch (err) { + console.log( + `Refresh token with userId ${ + req.user.id + } failed to be deleted at sign-out.` + ); + return next(err); + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/auth/sign-up.js b/src/routes/auth/sign-up.js index 8819b94..6bdf8a7 100644 --- a/src/routes/auth/sign-up.js +++ b/src/routes/auth/sign-up.js @@ -1,158 +1,158 @@ -const crypto = require('crypto'); - -const moment = require('moment'); -const { pick } = require('lodash'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { ActivationTicket } = require('../../models/activation-ticket'); -const { cleanSpaces, sendEmail } = require('../../helpers'); -const { User } = require('../../models/user'); - -const { validateSignUp } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateSignUp(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const data = pick(req.body, [ - 'email', - 'firstName', - 'isSubscribed', - 'lastName', - 'password' - ]); - data.firstName = cleanSpaces(data.firstName); - data.lastName = cleanSpaces(data.lastName); - data.username = `${slugify(data.firstName)}-${slugify(data.lastName)}`; - - let activationTicket; - try { - activationTicket = await ActivationTicket.findOne({ email: data.email }); - } catch (err) { - console.log( - `Activation ticket with email ${ - data.email - } failed to be found at sign-up.` - ); - return next(err); - } - - if (activationTicket) { - const expiresAt = moment(activationTicket.expiresAt).utc(); - const today = moment.utc(); - if (expiresAt.isBefore(today)) { - try { - await activationTicket.remove(); - } catch (err) { - console.log( - `Activation ticket with email ${ - activationTicket.email - } failed to be removed at sign-up.` - ); - return next(err); - } - } - } - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - $or: [{ email: data.email }, { username: data.username }], - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at sign-up.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - for (const user of repeatedUsers) { - if (user.email === data.email) { - return res.status(400).json({ email: 'Is already taken' }); - } - - let repeatedUser; - do { - data.username = `${slugify(data.firstName)}-${slugify( - data.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: data.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${data.username} failed to be found at sign-up.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === data.username); - } - } - - const today = moment.utc(); - const expiresAt = today.add(1, 'days').toDate(); - const key = `${crypto - .randomBytes(31) - .toString('hex')}${new Date().getTime().toString()}`; - - const activationTicketData = { - email: data.email, - expiresAt, - key, - userData: { - firstName: data.firstName, - isSubscribed: data.isSubscribed, - lastName: data.lastName, - password: data.password, - username: data.username - } - }; - try { - activationTicket = await ActivationTicket.create(activationTicketData); - } catch (err) { - console.log( - `Activation ticket failed to be created at sign-up.\nData: ${JSON.stringify( - activationTicketData - )}` - ); - return next(err); - } - - const subject = 'Activate Account'; - const htmlContent = ` -To activate your account use the link below:
-Stay awesome.
- `; - const textContent = ` - Welcome to AXS Map! - To activate your account use the link below: - ${process.env.API_URL}/auth/activate-account/${activationTicket.key} - Stay awesome. - `; - const receiversEmails = [activationTicket.email]; - - sendEmail({ - subject, - htmlContent, - textContent, - receiversEmails - }); - - return res.status(201).json({ general: 'Success' }); -}; +const crypto = require('crypto'); + +const moment = require('moment'); +const { pick } = require('lodash'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +const { ActivationTicket } = require('../../models/activation-ticket'); +const { cleanSpaces, sendEmail } = require('../../helpers'); +const { User } = require('../../models/user'); + +const { validateSignUp } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateSignUp(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const data = pick(req.body, [ + 'email', + 'firstName', + 'isSubscribed', + 'lastName', + 'password' + ]); + data.firstName = cleanSpaces(data.firstName); + data.lastName = cleanSpaces(data.lastName); + data.username = `${slugify(data.firstName)}-${slugify(data.lastName)}`; + + let activationTicket; + try { + activationTicket = await ActivationTicket.findOne({ email: data.email }); + } catch (err) { + console.log( + `Activation ticket with email ${ + data.email + } failed to be found at sign-up.` + ); + return next(err); + } + + if (activationTicket) { + const expiresAt = moment(activationTicket.expiresAt).utc(); + const today = moment.utc(); + if (expiresAt.isBefore(today)) { + try { + await activationTicket.remove(); + } catch (err) { + console.log( + `Activation ticket with email ${ + activationTicket.email + } failed to be removed at sign-up.` + ); + return next(err); + } + } + } + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + $or: [{ email: data.email }, { username: data.username }], + isArchived: false + }); + } catch (err) { + console.log('Users failed to be found at sign-up.'); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + for (const user of repeatedUsers) { + if (user.email === data.email) { + return res.status(400).json({ email: 'Is already taken' }); + } + + let repeatedUser; + do { + data.username = `${slugify(data.firstName)}-${slugify( + data.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}`; + + try { + repeatedUser = await User.findOne({ + username: data.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${data.username} failed to be found at sign-up.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === data.username); + } + } + + const today = moment.utc(); + const expiresAt = today.add(1, 'days').toDate(); + const key = `${crypto + .randomBytes(31) + .toString('hex')}${new Date().getTime().toString()}`; + + const activationTicketData = { + email: data.email, + expiresAt, + key, + userData: { + firstName: data.firstName, + isSubscribed: data.isSubscribed, + lastName: data.lastName, + password: data.password, + username: data.username + } + }; + try { + activationTicket = await ActivationTicket.create(activationTicketData); + } catch (err) { + console.log( + `Activation ticket failed to be created at sign-up.\nData: ${JSON.stringify( + activationTicketData + )}` + ); + return next(err); + } + + const subject = 'Activate Account'; + const htmlContent = ` +To activate your account use the link below:
+Stay awesome.
+ `; + const textContent = ` + Welcome to AXS Map! + To activate your account use the link below: + ${process.env.API_URL}/auth/activate-account/${activationTicket.key} + Stay awesome. + `; + const receiversEmails = [activationTicket.email]; + + sendEmail({ + subject, + htmlContent, + textContent, + receiversEmails + }); + + return res.status(201).json({ general: 'Success' }); +}; diff --git a/src/routes/auth/validations.js b/src/routes/auth/validations.js index f8bb8f4..7c11055 100644 --- a/src/routes/auth/validations.js +++ b/src/routes/auth/validations.js @@ -1,155 +1,155 @@ -const freemail = require('freemail'); -const { isEmail } = require('validator'); -const { isEmpty } = require('lodash'); - -const { cleanSpaces } = require('../../helpers'); - -module.exports = { - validateFacebookSignIn(data) { - const errors = {}; - - if (!data.code) { - errors.code = 'Is required'; - } else if (typeof data.code !== 'string') { - errors.code = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateForgottenPassword(data) { - const errors = {}; - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (!isEmail(data.email)) { - errors.email = 'Should be a valid email'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateGenerateToken(data) { - const errors = {}; - - if (!data.key) { - errors.key = 'Is required'; - } else if (typeof data.key !== 'string') { - errors.key = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateGoogleSignIn(data) { - const errors = {}; - - if (!data.code) { - errors.code = 'Is required'; - } else if (typeof data.code !== 'string') { - errors.code = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateResetPassword(data) { - const errors = {}; - - if (!data.key) { - errors.key = 'Is required'; - } else if (typeof data.key !== 'string') { - errors.key = 'Should be a string'; - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should have more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should have less than 31 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateSignIn(data) { - const errors = {}; - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateSignUp(data) { - const errors = {}; - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (cleanSpaces(data.email).length > 254) { - errors.email = 'Should have less than 255 characters'; - } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { - errors.email = 'Should be a valid email'; - } - - if (!data.firstName) { - errors.firstName = 'Is required'; - } else if (typeof data.firstName !== 'string') { - errors.firstName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { - errors.firstName = 'Should only have letters'; - } else if (cleanSpaces(data.firstName).length > 24) { - errors.firstName = 'Should have less than 25 characters'; - } else { - const firstName = cleanSpaces(data.firstName); - - if (firstName.split(' ').length > 1) { - errors.firstName = 'Should only be one name'; - } - } - - if (typeof data.isSubscribed === 'undefined') { - errors.isSubscribed = 'Is required'; - } else if (typeof data.isSubscribed !== 'boolean') { - errors.isSubscribed = 'Should be a boolean'; - } - - if (!data.lastName) { - errors.lastName = 'Is required'; - } else if (typeof data.lastName !== 'string') { - errors.lastName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { - errors.lastName = 'Should only have letters'; - } else if (cleanSpaces(data.lastName).length > 36) { - errors.lastName = 'Should have less than 37 characters'; - } else { - const lastName = cleanSpaces(data.lastName); - - if (lastName.split(' ').length > 1) { - errors.lastName = 'Should only be one surname'; - } - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should have more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should have less than 31 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const freemail = require('freemail'); +const { isEmail } = require('validator'); +const { isEmpty } = require('lodash'); + +const { cleanSpaces } = require('../../helpers'); + +module.exports = { + validateFacebookSignIn(data) { + const errors = {}; + + if (!data.code) { + errors.code = 'Is required'; + } else if (typeof data.code !== 'string') { + errors.code = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateForgottenPassword(data) { + const errors = {}; + + if (!data.email) { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } else if (!isEmail(data.email)) { + errors.email = 'Should be a valid email'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateGenerateToken(data) { + const errors = {}; + + if (!data.key) { + errors.key = 'Is required'; + } else if (typeof data.key !== 'string') { + errors.key = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateGoogleSignIn(data) { + const errors = {}; + + if (!data.code) { + errors.code = 'Is required'; + } else if (typeof data.code !== 'string') { + errors.code = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateResetPassword(data) { + const errors = {}; + + if (!data.key) { + errors.key = 'Is required'; + } else if (typeof data.key !== 'string') { + errors.key = 'Should be a string'; + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } else if (data.password.length < 8) { + errors.password = 'Should have more than 7 characters'; + } else if (data.password.length > 30) { + errors.password = 'Should have less than 31 characters'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateSignIn(data) { + const errors = {}; + + if (!data.email) { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateSignUp(data) { + const errors = {}; + + if (!data.email) { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } else if (cleanSpaces(data.email).length > 254) { + errors.email = 'Should have less than 255 characters'; + } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { + errors.email = 'Should be a valid email'; + } + + if (!data.firstName) { + errors.firstName = 'Is required'; + } else if (typeof data.firstName !== 'string') { + errors.firstName = 'Should be a string'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { + errors.firstName = 'Should only have letters'; + } else if (cleanSpaces(data.firstName).length > 24) { + errors.firstName = 'Should have less than 25 characters'; + } else { + const firstName = cleanSpaces(data.firstName); + + if (firstName.split(' ').length > 1) { + errors.firstName = 'Should only be one name'; + } + } + + if (typeof data.isSubscribed === 'undefined') { + errors.isSubscribed = 'Is required'; + } else if (typeof data.isSubscribed !== 'boolean') { + errors.isSubscribed = 'Should be a boolean'; + } + + if (!data.lastName) { + errors.lastName = 'Is required'; + } else if (typeof data.lastName !== 'string') { + errors.lastName = 'Should be a string'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { + errors.lastName = 'Should only have letters'; + } else if (cleanSpaces(data.lastName).length > 36) { + errors.lastName = 'Should have less than 37 characters'; + } else { + const lastName = cleanSpaces(data.lastName); + + if (lastName.split(' ').length > 1) { + errors.lastName = 'Should only be one surname'; + } + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } else if (data.password.length < 8) { + errors.password = 'Should have more than 7 characters'; + } else if (data.password.length > 30) { + errors.password = 'Should have less than 31 characters'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/events/create-event.js b/src/routes/events/create-event.js index 7b35bda..7787d3f 100644 --- a/src/routes/events/create-event.js +++ b/src/routes/events/create-event.js @@ -1,190 +1,184 @@ -const axios = require('axios'); -const FormData = require('form-data'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); - -const { validateCreateEvent } = require('./validations'); - -module.exports = async (req, res, next) => { - const data = { - address: req.body.address, - description: req.body.description, - donationAmounts: req.body.donationAmounts, - donationEnabled: req.body.donationEnabled, - donationGoal: req.body.donationGoal, - endDate: req.body.endDate, - isOpen: req.body.isOpen, - locationCoordinates: req.body.locationCoordinates, - name: req.body.name, - participantsGoal: req.body.participantsGoal, - poster: req.body.poster, - reviewsGoal: req.body.reviewsGoal, - startDate: req.body.startDate, - teamManager: req.body.teamManager - }; - - const { errors, isValid } = validateCreateEvent(data); - if (!isValid) return res.status(400).json(errors); - - data.address = cleanSpaces(data.address); - - data.endDate = moment(data.endDate) - .endOf('day') - .utc() - .toDate(); - - data.location = { - coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]] - }; - delete data.locationCoordinates; - - data.managers = [req.user.id]; - - data.name = cleanSpaces(data.name); - let repeatedEvent; - try { - repeatedEvent = await Event.findOne({ name: data.name, isArchived: false }); - } catch (err) { - console.log(`Event ${data.name} failed to be found at create-event`); - return next(err); - } - - if (repeatedEvent) { - return res.status(400).json({ name: 'Is already taken' }); - } - - if (data.poster) { - let poster; - try { - poster = await Photo.findOne({ url: data.poster }); - } catch (err) { - console.log(`Poster ${data.poster} failed to be found at create-event`); - return next(err); - } - - if (!poster) { - return res.status(404).json({ poster: 'Not found' }); - } - } - - data.startDate = moment(data.startDate) - .startOf('day') - .utc() - .toDate(); - - if (data.teamManager) { - let team; - try { - team = await Team.findOne({ _id: data.teamManager, isArchived: false }); - } catch (err) { - console.log( - `Team ${data.teamManager} failed to be found at create-event` - ); - return next(err); - } - - if (!team) { - return res.status(404).json({ teamManager: 'Not found' }); - } - - const teamManagers = team.managers.map(m => m.toString()); - if (!teamManagers.includes(req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - data.teamManager = undefined; - } - - if (data.donationEnabled) { - const campaignData = new FormData(); - campaignData.append('title', data.name); - campaignData.append('goal_in_cents', data.donationGoal * 100); - - let options = { - method: 'POST', - url: `https://${ - process.env.DONATELY_SUBDOMAIN - }.dntly.com/api/v1/admin/campaigns`, - headers: { - 'Content-Type': `multipart/form-data; boundary=${ - campaignData._boundary - }` - }, - auth: { - username: process.env.DONATELY_TOKEN, - password: '' - }, - data: campaignData - }; - - let response; - try { - response = await axios(options); - } catch (err) { - console.log('Donation campaign failed to be created at create-event.'); - return next(err); - } - - data.donationId = response.data.campaign.id; - } - - let event; - try { - event = await Event.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Event failed to be created at create-event.\nData: ${JSON.stringify( - data - )}` - ); - return next(err); - } - - req.user.events = [...req.user.events, event.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at create-event`); - return next(err); - } - - let eventLocation; - if (event.location.coordinates) { - eventLocation = { - lat: event.location.coordinates[1], - lng: event.location.coordinates[0] - }; - } - const dataResponse = { - id: event.id, - address: event.address, - description: event.description, - endDate: event.description, - isOpen: event.isOpen, - location: eventLocation, - managers: event.managers, - name: event.name, - participantsGoal: event.participantsGoal, - poster: event.poster, - reviewsGoal: event.reviewsGoal, - teamManager: event.teamManager - }; - - return res.status(201).json(dataResponse); -}; +const axios = require('axios'); +const FormData = require('form-data'); +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { Team } = require('../../models/team'); + +const { validateCreateEvent } = require('./validations'); + +module.exports = async (req, res, next) => { + const data = { + address: req.body.address, + description: req.body.description, + donationAmounts: req.body.donationAmounts, + donationEnabled: req.body.donationEnabled, + donationGoal: req.body.donationGoal, + endDate: req.body.endDate, + isOpen: req.body.isOpen, + locationCoordinates: req.body.locationCoordinates, + name: req.body.name, + participantsGoal: req.body.participantsGoal, + poster: req.body.poster, + reviewsGoal: req.body.reviewsGoal, + startDate: req.body.startDate, + teamManager: req.body.teamManager + }; + + const { errors, isValid } = validateCreateEvent(data); + if (!isValid) return res.status(400).json(errors); + + data.address = cleanSpaces(data.address); + + data.endDate = moment(data.endDate).endOf('day').utc().toDate(); + + data.location = { + coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]] + }; + delete data.locationCoordinates; + + data.managers = [req.user.id]; + + data.name = cleanSpaces(data.name); + let repeatedEvent; + try { + repeatedEvent = await Event.findOne({ name: data.name, isArchived: false }); + } catch (err) { + console.log(`Event ${data.name} failed to be found at create-event`); + return next(err); + } + + if (repeatedEvent) { + return res.status(400).json({ name: 'Is already taken' }); + } + + if (data.poster) { + let poster; + try { + poster = await Photo.findOne({ url: data.poster }); + } catch (err) { + console.log(`Poster ${data.poster} failed to be found at create-event`); + return next(err); + } + + if (!poster) { + return res.status(404).json({ poster: 'Not found' }); + } + } + + data.startDate = moment(data.startDate).startOf('day').utc().toDate(); + + if (data.teamManager) { + let team; + try { + team = await Team.findOne({ _id: data.teamManager, isArchived: false }); + } catch (err) { + console.log( + `Team ${data.teamManager} failed to be found at create-event` + ); + return next(err); + } + + if (!team) { + return res.status(404).json({ teamManager: 'Not found' }); + } + + const teamManagers = team.managers.map((m) => m.toString()); + if (!teamManagers.includes(req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else { + data.teamManager = undefined; + } + + if (data.donationEnabled) { + const campaignData = new FormData(); + campaignData.append('title', data.name); + campaignData.append('goal_in_cents', data.donationGoal * 100); + + let options = { + method: 'POST', + url: `https://${ + process.env.DONATELY_SUBDOMAIN + }.dntly.com/api/v1/admin/campaigns`, + headers: { + 'Content-Type': `multipart/form-data; boundary=${ + campaignData._boundary + }` + }, + auth: { + username: process.env.DONATELY_TOKEN, + password: '' + }, + data: campaignData + }; + + let response; + try { + response = await axios(options); + } catch (err) { + console.log('Donation campaign failed to be created at create-event.'); + return next(err); + } + + data.donationId = response.data.campaign.id; + } + + let event; + try { + event = await Event.create(data); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Event failed to be created at create-event.\nData: ${JSON.stringify( + data + )}` + ); + return next(err); + } + + req.user.events = [...req.user.events, event.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at create-event`); + return next(err); + } + + let eventLocation; + if (event.location.coordinates) { + eventLocation = { + lat: event.location.coordinates[1], + lng: event.location.coordinates[0] + }; + } + const dataResponse = { + id: event.id, + address: event.address, + description: event.description, + endDate: event.description, + isOpen: event.isOpen, + location: eventLocation, + managers: event.managers, + name: event.name, + participantsGoal: event.participantsGoal, + poster: event.poster, + reviewsGoal: event.reviewsGoal, + teamManager: event.teamManager + }; + + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/events/delete-event.js b/src/routes/events/delete-event.js index 17842f1..ca305ae 100644 --- a/src/routes/events/delete-event.js +++ b/src/routes/events/delete-event.js @@ -1,130 +1,130 @@ -const aws = require('aws-sdk'); -const { last } = require('lodash'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const s3 = new aws.S3(); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - console.log(`Event ${eventId} failed to be found at delete-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - if ( - !event.managers.find(m => m.toString() === req.user.id) && - !req.user.isAdmin - ) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - - if (endDate.isBefore(today) && event.reviews > 0) { - return res.status(423).json({ - general: - 'It cannot be removed because it already ended and has one or more reviews' - }); - } - - const participantsPromises = event.participants.map(p => - User.findOne({ _id: p.toString() }) - ); - - let participants; - try { - participants = await Promise.all(participantsPromises); - } catch (err) { - console.log('A participant failed to be found at delete-event'); - return next(err); - } - - for (const participant of participants) { - participant.events = participant.events.filter( - e => e.toString() !== event.id - ); - participant.updatedAt = moment.utc().toDate(); - - try { - await participant.save(); - } catch (err) { - console.log( - `Participant ${participant.id} failed to be updated at delete-event` - ); - return next(err); - } - } - - if (event.photos && event.photos.length > 0) { - for (const photo of event.photos) { - const photoParams = { - Bucket: process.env.AWS_S3_BUCKET, - Key: `events/photos/${last(photo.url.split('/'))}` - }; - - try { - await s3.deleteObject(photoParams).promise(); - } catch (err) { - console.log( - `Photo ${photoParams.Key} failed to be deleted at delete-event` - ); - return next(err); - } - } - } - - if (event.teams && event.teams.length > 0) { - const teamsPromises = event.teams.map(t => - Team.findOne({ _id: t.toString() }) - ); - - let teams; - try { - teams = await Promise.all(teamsPromises); - } catch (err) { - console.log('A team failed to be found at delete-event'); - return next(err); - } - - for (const team of teams) { - team.events = team.events.filter(e => e.toString() !== event.id); - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at delete-event`); - return next(err); - } - } - } - - try { - await event.remove(); - } catch (err) { - console.log(`Event ${event.id} failed to be removed at delete-event`); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const aws = require('aws-sdk'); +const { last } = require('lodash'); +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const s3 = new aws.S3(); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Event not found' }); + } + console.log(`Event ${eventId} failed to be found at delete-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + if ( + !event.managers.find((m) => m.toString() === req.user.id) && + !req.user.isAdmin + ) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + + if (endDate.isBefore(today) && event.reviews > 0) { + return res.status(423).json({ + general: + 'It cannot be removed because it already ended and has one or more reviews' + }); + } + + const participantsPromises = event.participants.map((p) => + User.findOne({ _id: p.toString() }) + ); + + let participants; + try { + participants = await Promise.all(participantsPromises); + } catch (err) { + console.log('A participant failed to be found at delete-event'); + return next(err); + } + + for (const participant of participants) { + participant.events = participant.events.filter( + (e) => e.toString() !== event.id + ); + participant.updatedAt = moment.utc().toDate(); + + try { + await participant.save(); + } catch (err) { + console.log( + `Participant ${participant.id} failed to be updated at delete-event` + ); + return next(err); + } + } + + if (event.photos && event.photos.length > 0) { + for (const photo of event.photos) { + const photoParams = { + Bucket: process.env.AWS_S3_BUCKET, + Key: `events/photos/${last(photo.url.split('/'))}` + }; + + try { + await s3.deleteObject(photoParams).promise(); + } catch (err) { + console.log( + `Photo ${photoParams.Key} failed to be deleted at delete-event` + ); + return next(err); + } + } + } + + if (event.teams && event.teams.length > 0) { + const teamsPromises = event.teams.map((t) => + Team.findOne({ _id: t.toString() }) + ); + + let teams; + try { + teams = await Promise.all(teamsPromises); + } catch (err) { + console.log('A team failed to be found at delete-event'); + return next(err); + } + + for (const team of teams) { + team.events = team.events.filter((e) => e.toString() !== event.id); + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at delete-event`); + return next(err); + } + } + } + + try { + await event.remove(); + } catch (err) { + console.log(`Event ${event.id} failed to be removed at delete-event`); + return next(err); + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/events/edit-event.js b/src/routes/events/edit-event.js index 29368ab..96aa7e2 100644 --- a/src/routes/events/edit-event.js +++ b/src/routes/events/edit-event.js @@ -1,387 +1,377 @@ -const { difference, intersection } = require('lodash'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateEditEvent } = require('./validations'); - -module.exports = async (req, res, next) => { - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - - console.log(`Event ${eventId} failed to be found at edit-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const data = { - address: req.body.address, - description: req.body.description, - endDate: req.body.endDate, - isOpen: req.body.isOpen, - locationCoordinates: req.body.locationCoordinates, - managers: req.body.managers, - name: req.body.name, - participants: req.body.participants, - participantsGoal: req.body.participantsGoal, - poster: req.body.poster, - reviewsGoal: req.body.reviewsGoal, - startDate: req.body.startDate, - teamManager: req.body.teamManager, - teams: req.body.teams - }; - - const { errors, isValid } = validateEditEvent(data); - if (!isValid) return res.status(400).json(errors); - - event.address = data.address ? cleanSpaces(data.address) : event.address; - event.description = data.description || event.description; - - if (data.endDate) { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const startDate = moment(event.startDate) - .startOf('day') - .utc(); - - if (!data.startDate) { - if (endDate.isBefore(startDate)) { - return res.status(400).json({ - endDate: 'Should be equal to or greater than startDate' - }); - } else if (endDate.diff(startDate, 'days') > 365) { - return res.status(400).json({ - endDate: 'Should last less than 365 days from startDate' - }); - } - } - - event.endDate = endDate.toDate(); - } - - event.isOpen = - typeof data.isOpen !== 'undefined' ? data.isOpen : event.isOpen; - - if (data.locationCoordinates && data.locationCoordinates.length > 0) { - event.location = { - coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]], - type: 'Point' - }; - } - - if (data.managers) { - let managersToAdd = []; - let managersToRemove = []; - - data.managers.forEach(m => { - if (m.startsWith('-')) { - managersToRemove = [...managersToRemove, m.substring(1)]; - } else { - managersToAdd = [...managersToAdd, m]; - } - }); - - const eventManagers = event.managers.map(m => m.toString()); - - managersToAdd = [...new Set(difference(managersToAdd, eventManagers))]; - if (managersToAdd.length > 0) { - const eventParticipants = event.participants.map(p => p.toString()); - const notParticipant = managersToAdd.find( - m => !eventParticipants.includes(m) - ); - - if (notParticipant) { - return res.status(400).json({ - managers: `User ${notParticipant} is not a participant of this event` - }); - } - - event.managers = [...eventManagers, ...managersToAdd]; - event.participants = event.participants.filter( - p => !managersToAdd.includes(p.toString()) - ); - } - - managersToRemove = [ - ...new Set(intersection(managersToRemove, eventManagers)) - ]; - if (managersToRemove.length === event.managers.length) { - return res - .status(400) - .json({ managers: 'Should not remove all managers' }); - } - - event.managers = event.managers.filter( - m => !managersToRemove.includes(m.toString()) - ); - const eventParticipants = event.participants.map(p => p.toString()); - event.participants = [...eventParticipants, ...managersToRemove]; - } - - if (data.name) { - const eventName = cleanSpaces(data.name); - - if (eventName !== event.name) { - let repeatedEvent; - try { - repeatedEvent = await Event.findOne({ - name: eventName, - isArchived: false - }); - } catch (err) { - console.log(`Event ${eventName} failed to be found at edit-event`); - return next(err); - } - - if (repeatedEvent) { - return res.status(400).json({ name: 'Is already taken' }); - } - - event.name = eventName; - } - } - - if (data.participants) { - const eventParticipants = event.participants.map(p => p.toString()); - let participantsToRemove = data.participants.map(p => p.substring(1)); - participantsToRemove = [ - ...new Set(intersection(participantsToRemove, eventParticipants)) - ]; - - const getParticipants = participantsToRemove.map(p => - User.find({ _id: p, isArchived: false }) - ); - let participants; - try { - participants = await Promise.all(getParticipants); - } catch (err) { - console.log('Participants failed to be found at edit-event'); - return next(err); - } - - const updateParticipants = participants.map((p, i) => { - p[i].events = p[i].events.filter(e => e.toString() !== event.id); - return p[i].save(); - }); - - try { - await Promise.all(updateParticipants); - } catch (err) { - console.log('Participants failed to be updated at edit-event'); - return next(err); - } - - event.participants = event.participants.filter( - p => !participantsToRemove.includes(p.toString()) - ); - } - - event.participantsGoal = data.participantsGoal || event.participantsGoal; - - if ( - data.poster && - !data.poster.includes('default') && - data.poster !== event.poster - ) { - let poster; - try { - poster = await Photo.findOne({ url: data.poster }); - } catch (err) { - console.log(`Poster ${data.poster} failed to be found at edit-event`); - return next(err); - } - - if (!poster) { - return res.status(404).json({ poster: 'Not found' }); - } - - event.poster = data.poster; - } else if (data.poster === '') { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`; - } - - event.reviewsGoal = data.reviewsGoal || event.reviewsGoal; - - if (data.startDate) { - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - const endDate = moment(event.endDate) - .endOf('day') - .utc(); - - if (!data.endDate) { - const today = moment() - .startOf('day') - .utc(); - - if (startDate.isBefore(today)) { - return res.status(400).json({ - startDate: 'Should be equal to or greater than the current time' - }); - } else if (startDate.isAfter(endDate)) { - return res.status(400).json({ - startDate: 'Should be equal to or less than endDate' - }); - } else if (endDate.diff(startDate, 'days') > 365) { - return res.status(400).json({ - startDate: 'Should last less than 365 days to endDate' - }); - } - } - - event.startDate = startDate.toDate(); - } - - if (data.teamManager) { - let team; - try { - team = await Team.findOne({ _id: data.teamManager, isArchived: false }); - } catch (err) { - console.log(`Team ${data.teamManager} failed to be found at edit-event`); - return next(err); - } - - if (!team) { - return res.status(404).json({ teamManager: 'Not found' }); - } - - const teamManagers = team.managers.map(m => m.toString()); - if (!teamManagers.includes(req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - event.teamManager = data.teamManager; - - team.events = [...new Set([...team.events, event.id])]; - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at edit-event`); - return next(err); - } - } else if (data.teamManager === '' && event.teamManager) { - let team; - try { - team = await Team.findOne({ _id: event.teamManager, isArchived: false }); - } catch (err) { - console.log(`Team ${event.teamManager} failed to be found at edit-event`); - return next(err); - } - - if (!team) { - return res.status(404).json({ teamManager: 'Not found' }); - } - - const teamManagers = team.managers.map(m => m.toString()); - if (!teamManagers.includes(req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - event.teamManager = null; - - team.events = team.events.filter(e => e.toString() !== event.id); - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at edit-event`); - return next(err); - } - } - - if (data.teams) { - const eventTeams = event.teams.map(t => t.toString()); - let teamsToRemove = data.teams.map(t => t.substring(1)); - teamsToRemove = [...new Set(intersection(teamsToRemove, eventTeams))]; - - const getTeams = teamsToRemove.map(t => - Team.find({ _id: t, isArchived: false }) - ); - let teams; - try { - teams = await Promise.all(getTeams); - } catch (err) { - console.log('Teams failed to be found at edit-event'); - return next(err); - } - - const updateTeams = teams.map((t, i) => { - t[i].events = t[i].events.filter(e => e.toString() !== event.id); - return t[i].save(); - }); - - try { - await Promise.all(updateTeams); - } catch (err) { - console.log('Teams failed to be updated at edit-event'); - return next(err); - } - - event.teams = event.teams.filter( - t => !teamsToRemove.includes(t.toString()) - ); - } - - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Event ${event.id} failed to be updated at edit-event`); - return next(err); - } - - let eventLocation; - if (event.location.coordinates) { - eventLocation = { - lat: event.location.coordinates[1], - lng: event.location.coordinates[0] - }; - } - const dataResponse = { - address: event.address, - description: event.description, - endDate: event.description, - isOpen: event.isOpen, - location: eventLocation, - managers: event.managers, - name: event.name, - participantsGoal: event.participantsGoal, - poster: event.poster, - reviewsGoal: event.reviewsGoal, - teamManager: event.teamManager - }; - - return res.status(200).json(dataResponse); -}; +const { difference, intersection } = require('lodash'); +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const { validateEditEvent } = require('./validations'); + +module.exports = async (req, res, next) => { + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Event not found' }); + } + + console.log(`Event ${eventId} failed to be found at edit-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const data = { + address: req.body.address, + description: req.body.description, + endDate: req.body.endDate, + isOpen: req.body.isOpen, + locationCoordinates: req.body.locationCoordinates, + managers: req.body.managers, + name: req.body.name, + participants: req.body.participants, + participantsGoal: req.body.participantsGoal, + poster: req.body.poster, + reviewsGoal: req.body.reviewsGoal, + startDate: req.body.startDate, + teamManager: req.body.teamManager, + teams: req.body.teams + }; + + const { errors, isValid } = validateEditEvent(data); + if (!isValid) return res.status(400).json(errors); + + event.address = data.address ? cleanSpaces(data.address) : event.address; + event.description = data.description || event.description; + + if (data.endDate) { + const endDate = moment(data.endDate).endOf('day').utc(); + const startDate = moment(event.startDate).startOf('day').utc(); + + if (!data.startDate) { + if (endDate.isBefore(startDate)) { + return res.status(400).json({ + endDate: 'Should be equal to or greater than startDate' + }); + } else if (endDate.diff(startDate, 'days') > 365) { + return res.status(400).json({ + endDate: 'Should last less than 365 days from startDate' + }); + } + } + + event.endDate = endDate.toDate(); + } + + event.isOpen = + typeof data.isOpen !== 'undefined' ? data.isOpen : event.isOpen; + + if (data.locationCoordinates && data.locationCoordinates.length > 0) { + event.location = { + coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]], + type: 'Point' + }; + } + + if (data.managers) { + let managersToAdd = []; + let managersToRemove = []; + + data.managers.forEach((m) => { + if (m.startsWith('-')) { + managersToRemove = [...managersToRemove, m.substring(1)]; + } else { + managersToAdd = [...managersToAdd, m]; + } + }); + + const eventManagers = event.managers.map((m) => m.toString()); + + managersToAdd = [...new Set(difference(managersToAdd, eventManagers))]; + if (managersToAdd.length > 0) { + const eventParticipants = event.participants.map((p) => p.toString()); + const notParticipant = managersToAdd.find( + (m) => !eventParticipants.includes(m) + ); + + if (notParticipant) { + return res.status(400).json({ + managers: `User ${notParticipant} is not a participant of this event` + }); + } + + event.managers = [...eventManagers, ...managersToAdd]; + event.participants = event.participants.filter( + (p) => !managersToAdd.includes(p.toString()) + ); + } + + managersToRemove = [ + ...new Set(intersection(managersToRemove, eventManagers)) + ]; + if (managersToRemove.length === event.managers.length) { + return res + .status(400) + .json({ managers: 'Should not remove all managers' }); + } + + event.managers = event.managers.filter( + (m) => !managersToRemove.includes(m.toString()) + ); + const eventParticipants = event.participants.map((p) => p.toString()); + event.participants = [...eventParticipants, ...managersToRemove]; + } + + if (data.name) { + const eventName = cleanSpaces(data.name); + + if (eventName !== event.name) { + let repeatedEvent; + try { + repeatedEvent = await Event.findOne({ + name: eventName, + isArchived: false + }); + } catch (err) { + console.log(`Event ${eventName} failed to be found at edit-event`); + return next(err); + } + + if (repeatedEvent) { + return res.status(400).json({ name: 'Is already taken' }); + } + + event.name = eventName; + } + } + + if (data.participants) { + const eventParticipants = event.participants.map((p) => p.toString()); + let participantsToRemove = data.participants.map((p) => p.substring(1)); + participantsToRemove = [ + ...new Set(intersection(participantsToRemove, eventParticipants)) + ]; + + const getParticipants = participantsToRemove.map((p) => + User.find({ _id: p, isArchived: false }) + ); + let participants; + try { + participants = await Promise.all(getParticipants); + } catch (err) { + console.log('Participants failed to be found at edit-event'); + return next(err); + } + + const updateParticipants = participants.map((p, i) => { + p[i].events = p[i].events.filter((e) => e.toString() !== event.id); + return p[i].save(); + }); + + try { + await Promise.all(updateParticipants); + } catch (err) { + console.log('Participants failed to be updated at edit-event'); + return next(err); + } + + event.participants = event.participants.filter( + (p) => !participantsToRemove.includes(p.toString()) + ); + } + + event.participantsGoal = data.participantsGoal || event.participantsGoal; + + if ( + data.poster && + !data.poster.includes('default') && + data.poster !== event.poster + ) { + let poster; + try { + poster = await Photo.findOne({ url: data.poster }); + } catch (err) { + console.log(`Poster ${data.poster} failed to be found at edit-event`); + return next(err); + } + + if (!poster) { + return res.status(404).json({ poster: 'Not found' }); + } + + event.poster = data.poster; + } else if (data.poster === '') { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`; + } + + event.reviewsGoal = data.reviewsGoal || event.reviewsGoal; + + if (data.startDate) { + const startDate = moment(data.startDate).startOf('day').utc(); + const endDate = moment(event.endDate).endOf('day').utc(); + + if (!data.endDate) { + const today = moment().startOf('day').utc(); + + if (startDate.isBefore(today)) { + return res.status(400).json({ + startDate: 'Should be equal to or greater than the current time' + }); + } else if (startDate.isAfter(endDate)) { + return res.status(400).json({ + startDate: 'Should be equal to or less than endDate' + }); + } else if (endDate.diff(startDate, 'days') > 365) { + return res.status(400).json({ + startDate: 'Should last less than 365 days to endDate' + }); + } + } + + event.startDate = startDate.toDate(); + } + + if (data.teamManager) { + let team; + try { + team = await Team.findOne({ _id: data.teamManager, isArchived: false }); + } catch (err) { + console.log(`Team ${data.teamManager} failed to be found at edit-event`); + return next(err); + } + + if (!team) { + return res.status(404).json({ teamManager: 'Not found' }); + } + + const teamManagers = team.managers.map((m) => m.toString()); + if (!teamManagers.includes(req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + event.teamManager = data.teamManager; + + team.events = [...new Set([...team.events, event.id])]; + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at edit-event`); + return next(err); + } + } else if (data.teamManager === '' && event.teamManager) { + let team; + try { + team = await Team.findOne({ _id: event.teamManager, isArchived: false }); + } catch (err) { + console.log(`Team ${event.teamManager} failed to be found at edit-event`); + return next(err); + } + + if (!team) { + return res.status(404).json({ teamManager: 'Not found' }); + } + + const teamManagers = team.managers.map((m) => m.toString()); + if (!teamManagers.includes(req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + event.teamManager = null; + + team.events = team.events.filter((e) => e.toString() !== event.id); + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at edit-event`); + return next(err); + } + } + + if (data.teams) { + const eventTeams = event.teams.map((t) => t.toString()); + let teamsToRemove = data.teams.map((t) => t.substring(1)); + teamsToRemove = [...new Set(intersection(teamsToRemove, eventTeams))]; + + const getTeams = teamsToRemove.map((t) => + Team.find({ _id: t, isArchived: false }) + ); + let teams; + try { + teams = await Promise.all(getTeams); + } catch (err) { + console.log('Teams failed to be found at edit-event'); + return next(err); + } + + const updateTeams = teams.map((t, i) => { + t[i].events = t[i].events.filter((e) => e.toString() !== event.id); + return t[i].save(); + }); + + try { + await Promise.all(updateTeams); + } catch (err) { + console.log('Teams failed to be updated at edit-event'); + return next(err); + } + + event.teams = event.teams.filter( + (t) => !teamsToRemove.includes(t.toString()) + ); + } + + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Event ${event.id} failed to be updated at edit-event`); + return next(err); + } + + let eventLocation; + if (event.location.coordinates) { + eventLocation = { + lat: event.location.coordinates[1], + lng: event.location.coordinates[0] + }; + } + const dataResponse = { + address: event.address, + description: event.description, + endDate: event.description, + isOpen: event.isOpen, + location: eventLocation, + managers: event.managers, + name: event.name, + participantsGoal: event.participantsGoal, + poster: event.poster, + reviewsGoal: event.reviewsGoal, + teamManager: event.teamManager + }; + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/events/get-event.js b/src/routes/events/get-event.js index eb8bd3a..c07a89d 100644 --- a/src/routes/events/get-event.js +++ b/src/routes/events/get-event.js @@ -1,207 +1,207 @@ -const axios = require('axios'); -const mongoose = require('mongoose'); -const { isMongoId } = require('validator'); - -const { Event } = require('../../models/event'); - -module.exports = async (req, res, next) => { - let eventId = req.params.eventId; - if (!isMongoId(eventId)) { - return res.status(400).json({ general: 'Event not found' }); - } - eventId = mongoose.Types.ObjectId(eventId); - - let event; - try { - event = await Event.aggregate([ - { - $match: { _id: eventId } - }, - { - $lookup: { - from: 'users', - let: { managers: '$managers' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$managers'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'managers' - } - }, - { - $lookup: { - from: 'users', - let: { participants: '$participants' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$participants'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'participants' - } - }, - { - $lookup: { - from: 'teams', - let: { teams: '$teams' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$teams'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'teams' - } - }, - { - $lookup: { - from: 'teams', - let: { teamManager: '$teamManager' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$teamManager'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'teamManager' - } - }, - { - $unwind: { - path: '$teamManager', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'events', - let: { reviewsAmount: '$reviewsAmount' }, - pipeline: [ - { - $match: { - $expr: { - $gt: ['$reviewsAmount', '$$reviewsAmount'] - } - } - }, - { - $count: 'ranking' - } - ], - as: 'ranking' - } - }, - { - $project: { - _id: 0, - id: '$_id', - address: 1, - description: 1, - donationAmounts: 1, - donationId: 1, - endDate: 1, - isOpen: 1, - location: 1, - managers: 1, - name: 1, - participants: 1, - participantsGoal: 1, - poster: 1, - ranking: 1, - reviewsAmount: 1, - reviewsGoal: 1, - startDate: 1, - teamManager: 1, - teams: 1 - } - } - ]); - } catch (err) { - console.log(`Event ${eventId} failed to be found at get-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - const dataResponse = Object.assign({}, event[0], { - ranking: event[0].ranking.length ? event[0].ranking[0].ranking + 1 : 1 - }); - - if (dataResponse.donationId) { - let options = { - method: 'GET', - url: `https://${ - process.env.DONATELY_SUBDOMAIN - }.dntly.com/api/v1/admin/campaigns/${dataResponse.donationId}`, - auth: { - username: process.env.DONATELY_TOKEN, - password: '' - } - }; - - let response; - try { - response = await axios(options); - } catch (err) { - console.log('Donation campaign failed to be found at get-event.'); - return next(err); - } - - dataResponse.donationAmountRaised = response.data.campaign.amount_raised; - dataResponse.donationDonorsCount = response.data.campaign.donors_count; - dataResponse.donationGoal = response.data.campaign.campaign_goal; - } - - return res.status(200).json(dataResponse); -}; +const axios = require('axios'); +const mongoose = require('mongoose'); +const { isMongoId } = require('validator'); + +const { Event } = require('../../models/event'); + +module.exports = async (req, res, next) => { + let eventId = req.params.eventId; + if (!isMongoId(eventId)) { + return res.status(400).json({ general: 'Event not found' }); + } + eventId = new mongoose.Types.ObjectId(eventId); + + let event; + try { + event = await Event.aggregate([ + { + $match: { _id: eventId } + }, + { + $lookup: { + from: 'users', + let: { managers: '$managers' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$managers'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'managers' + } + }, + { + $lookup: { + from: 'users', + let: { participants: '$participants' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$participants'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'participants' + } + }, + { + $lookup: { + from: 'teams', + let: { teams: '$teams' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$teams'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + name: 1 + } + } + ], + as: 'teams' + } + }, + { + $lookup: { + from: 'teams', + let: { teamManager: '$teamManager' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$teamManager'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + name: 1 + } + } + ], + as: 'teamManager' + } + }, + { + $unwind: { + path: '$teamManager', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'events', + let: { reviewsAmount: '$reviewsAmount' }, + pipeline: [ + { + $match: { + $expr: { + $gt: ['$reviewsAmount', '$$reviewsAmount'] + } + } + }, + { + $count: 'ranking' + } + ], + as: 'ranking' + } + }, + { + $project: { + _id: 0, + id: '$_id', + address: 1, + description: 1, + donationAmounts: 1, + donationId: 1, + endDate: 1, + isOpen: 1, + location: 1, + managers: 1, + name: 1, + participants: 1, + participantsGoal: 1, + poster: 1, + ranking: 1, + reviewsAmount: 1, + reviewsGoal: 1, + startDate: 1, + teamManager: 1, + teams: 1 + } + } + ]); + } catch (err) { + console.log(`Event ${eventId} failed to be found at get-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + const dataResponse = Object.assign({}, event[0], { + ranking: event[0].ranking.length ? event[0].ranking[0].ranking + 1 : 1 + }); + + if (dataResponse.donationId) { + let options = { + method: 'GET', + url: `https://${ + process.env.DONATELY_SUBDOMAIN + }.dntly.com/api/v1/admin/campaigns/${dataResponse.donationId}`, + auth: { + username: process.env.DONATELY_TOKEN, + password: '' + } + }; + + let response; + try { + response = await axios(options); + } catch (err) { + console.log('Donation campaign failed to be found at get-event.'); + return next(err); + } + + dataResponse.donationAmountRaised = response.data.campaign.amount_raised; + dataResponse.donationDonorsCount = response.data.campaign.donors_count; + dataResponse.donationGoal = response.data.campaign.campaign_goal; + } + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/events/index.js b/src/routes/events/index.js index fbbe43d..901a189 100644 --- a/src/routes/events/index.js +++ b/src/routes/events/index.js @@ -1,31 +1,31 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createEvent = require('./create-event'); -const deleteEvent = require('./delete-event'); -const editEvent = require('./edit-event'); -const getEvent = require('./get-event'); -const leaveEvent = require('./leave-event'); -const listEvents = require('./list-events'); -const joinEvent = require('./join-event'); - -const router = new express.Router(); - -router.get('', listEvents); -router.post('', isAuthenticated({ isOptional: false }), createEvent); -router.get('/:eventId', getEvent); -router.put('/:eventId', isAuthenticated({ isOptional: false }), editEvent); -router.delete('/:eventId', isAuthenticated({ isOptional: false }), deleteEvent); -router.post( - '/:eventId/join', - isAuthenticated({ isOptional: false }), - joinEvent -); -router.put( - '/:eventId/leave', - isAuthenticated({ isOptional: false }), - leaveEvent -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const createEvent = require('./create-event'); +const deleteEvent = require('./delete-event'); +const editEvent = require('./edit-event'); +const getEvent = require('./get-event'); +const leaveEvent = require('./leave-event'); +const listEvents = require('./list-events'); +const joinEvent = require('./join-event'); + +const router = new express.Router(); + +router.get('', listEvents); +router.post('', isAuthenticated({ isOptional: false }), createEvent); +router.get('/:eventId', getEvent); +router.put('/:eventId', isAuthenticated({ isOptional: false }), editEvent); +router.delete('/:eventId', isAuthenticated({ isOptional: false }), deleteEvent); +router.post( + '/:eventId/join', + isAuthenticated({ isOptional: false }), + joinEvent +); +router.put( + '/:eventId/leave', + isAuthenticated({ isOptional: false }), + leaveEvent +); + +module.exports = router; diff --git a/src/routes/events/join-event.js b/src/routes/events/join-event.js index 91b4f1e..f3b6378 100644 --- a/src/routes/events/join-event.js +++ b/src/routes/events/join-event.js @@ -1,134 +1,134 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); - -module.exports = async (req, res, next) => { - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - - console.log(`Event ${eventId} failed to be found at join-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - const eventParticipants = event.participants.map(p => p.toString()); - if (eventParticipants.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a participant in this event' }); - } - - const eventManagers = event.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a participant in this event' }); - } - - if (event.isOpen) { - req.user.events = [...req.user.events, event.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at join-event`); - return next(err); - } - - event.participants = [...event.participants, req.user.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log(`Event ${event.id} failed to be updated at join-event`); - return next(err); - } - - return res.status(200).json({ general: 'Joined' }); - } else { - let petition; - try { - petition = await Petition.findOne({ - event: event.id, - sender: req.user.id, - type: 'request-user-event' - }); - } catch (err) { - console.log( - `Petition from user ${req.user.id} to event ${ - event.id - } failed to be found at join-event` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'You already have a pending petition with this event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at join-event` - ); - return next(err); - } - } - - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - if (endDate.isBefore(today)) { - return res - .status(423) - .json({ general: 'This event has already finished' }); - } - - const petitionData = { - event: event.id, - sender: req.user.id, - type: 'request-user-event' - }; - try { - await Petition.create(petitionData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Petition failed to be created at join-event.\nData: ${JSON.stringify( - petitionData - )}` - ); - return next(err); - } - - return res.status(200).json({ general: 'Requested' }); - } -}; +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Petition } = require('../../models/petition'); + +module.exports = async (req, res, next) => { + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Event not found' }); + } + + console.log(`Event ${eventId} failed to be found at join-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + const eventParticipants = event.participants.map((p) => p.toString()); + if (eventParticipants.includes(req.user.id)) { + return res + .status(400) + .json({ general: 'You already are a participant in this event' }); + } + + const eventManagers = event.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + return res + .status(400) + .json({ general: 'You already are a participant in this event' }); + } + + if (event.isOpen) { + req.user.events = [...req.user.events, event.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at join-event`); + return next(err); + } + + event.participants = [...event.participants, req.user.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log(`Event ${event.id} failed to be updated at join-event`); + return next(err); + } + + return res.status(200).json({ general: 'Joined' }); + } else { + let petition; + try { + petition = await Petition.findOne({ + event: event.id, + sender: req.user.id, + type: 'request-user-event' + }); + } catch (err) { + console.log( + `Petition from user ${req.user.id} to event ${ + event.id + } failed to be found at join-event` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'You already have a pending petition with this event' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at join-event` + ); + return next(err); + } + } + + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + if (endDate.isBefore(today)) { + return res + .status(423) + .json({ general: 'This event has already finished' }); + } + + const petitionData = { + event: event.id, + sender: req.user.id, + type: 'request-user-event' + }; + try { + await Petition.create(petitionData); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Petition failed to be created at join-event.\nData: ${JSON.stringify( + petitionData + )}` + ); + return next(err); + } + + return res.status(200).json({ general: 'Requested' }); + } +}; diff --git a/src/routes/events/leave-event.js b/src/routes/events/leave-event.js index 5b4e0fd..17dc445 100644 --- a/src/routes/events/leave-event.js +++ b/src/routes/events/leave-event.js @@ -1,69 +1,69 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); - -module.exports = async (req, res, next) => { - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - - console.log(`Event ${eventId} failed to be found at leave-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - - if (endDate.isBefore(today)) { - return res.status(400).json({ - general: 'You cannot leave because it already ended' - }); - } - - if (event.managers.find(m => m.toString() === req.user.id)) { - event.managers = event.managers.filter(m => m.toString() !== req.user.id); - - if (event.managers.length === 0) { - return res.status(400).json({ - general: 'You cannot leave because you are the only manager' - }); - } - } else if (event.participants.find(p => p.toString() === req.user.id)) { - event.participants = event.participants.filter( - p => p.toString() !== req.user.id - ); - } else { - return res.status(400).json({ general: 'You are not a participant' }); - } - - event.updatedAt = today.toDate(); - - try { - await event.save(); - } catch (err) { - console.log(`Event ${event.id} failed to be updated at leave-event`); - return next(err); - } - - req.user.events = req.user.events.filter(e => e.toString() !== event.id); - req.user.updatedAt = today.toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at leave-event`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Event } = require('../../models/event'); + +module.exports = async (req, res, next) => { + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Event not found' }); + } + + console.log(`Event ${eventId} failed to be found at leave-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + + if (endDate.isBefore(today)) { + return res.status(400).json({ + general: 'You cannot leave because it already ended' + }); + } + + if (event.managers.find((m) => m.toString() === req.user.id)) { + event.managers = event.managers.filter((m) => m.toString() !== req.user.id); + + if (event.managers.length === 0) { + return res.status(400).json({ + general: 'You cannot leave because you are the only manager' + }); + } + } else if (event.participants.find((p) => p.toString() === req.user.id)) { + event.participants = event.participants.filter( + (p) => p.toString() !== req.user.id + ); + } else { + return res.status(400).json({ general: 'You are not a participant' }); + } + + event.updatedAt = today.toDate(); + + try { + await event.save(); + } catch (err) { + console.log(`Event ${event.id} failed to be updated at leave-event`); + return next(err); + } + + req.user.events = req.user.events.filter((e) => e.toString() !== event.id); + req.user.updatedAt = today.toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at leave-event`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/events/list-events.js b/src/routes/events/list-events.js index 9521d85..7f75d82 100644 --- a/src/routes/events/list-events.js +++ b/src/routes/events/list-events.js @@ -1,95 +1,88 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); - -const { validateListEvents } = require('./validations'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - - const { errors, isValid } = validateListEvents(queryParams); - if (!isValid) return res.status(400).json(errors); - - const eventsQuery = {}; - - if (queryParams.keywords) { - eventsQuery.$text = { $search: queryParams.keywords }; - } - - eventsQuery.isArchived = false; - - let afterDate; - let beforeDate; - if (queryParams.afterDate && queryParams.beforeDate) { - afterDate = moment(queryParams.afterDate) - .utc() - .toDate(); - beforeDate = moment(queryParams.beforeDate) - .utc() - .toDate(); - - eventsQuery.startDate = { $gte: afterDate, $lte: beforeDate }; - } else if (queryParams.afterDate) { - afterDate = moment(queryParams.afterDate) - .utc() - .toDate(); - eventsQuery.startDate = { $gte: afterDate }; - } else if (queryParams.beforeDate) { - beforeDate = moment(queryParams.beforeDate) - .utc() - .toDate(); - eventsQuery.startDate = { $lte: beforeDate }; - } - - let sortBy = queryParams.sortBy || '-startDate'; - let page = queryParams.page ? queryParams.page - 1 : 0; - const pageLimit = queryParams.pageLimit || 12; - - let events; - let total; - try { - [events, total] = await Promise.all([ - Event.aggregate() - .match(eventsQuery) - .project({ - _id: 0, - id: '$_id', - address: 1, - endDate: 1, - name: 1, - poster: 1, - reviewsAmount: 1, - reviewsGoal: 1, - startDate: 1 - }) - .sort(sortBy) - .skip(page * pageLimit) - .limit(pageLimit), - Event.find(eventsQuery).count() - ]); - } catch (err) { - console.log('Events failed to be found or count at list-events'); - return next(err); - } - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - return res.status(200).json({ - page: page + 1, - lastPage, - pageLimit, - total, - sortBy, - results: events - }); -}; +const moment = require("moment"); + +const { Event } = require("../../models/event"); + +const { validateListEvents } = require("./validations"); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListEvents(queryParams); + if (!isValid) return res.status(400).json(errors); + + const eventsQuery = {}; + + if (queryParams.keywords) { + eventsQuery.$text = { $search: queryParams.keywords }; + } + + eventsQuery.isArchived = false; + + let afterDate; + let beforeDate; + if (queryParams.afterDate && queryParams.beforeDate) { + afterDate = moment(queryParams.afterDate).utc().toDate(); + beforeDate = moment(queryParams.beforeDate).utc().toDate(); + + eventsQuery.startDate = { $gte: afterDate, $lte: beforeDate }; + } else if (queryParams.afterDate) { + afterDate = moment(queryParams.afterDate).utc().toDate(); + eventsQuery.startDate = { $gte: afterDate }; + } else if (queryParams.beforeDate) { + beforeDate = moment(queryParams.beforeDate).utc().toDate(); + eventsQuery.startDate = { $lte: beforeDate }; + } + + let sortBy = queryParams.sortBy || "-startDate"; + let page = queryParams.page ? queryParams.page - 1 : 0; + const pageLimit = queryParams.pageLimit || 12; + + let events; + let total; + try { + [events, total] = await Promise.all([ + Event.aggregate() + .match(eventsQuery) + .project({ + _id: 0, + id: "$_id", + address: 1, + endDate: 1, + name: 1, + poster: 1, + reviewsAmount: 1, + reviewsGoal: 1, + startDate: 1, + description: 1, + }) + .sort(sortBy) + .skip(page * pageLimit) + .limit(pageLimit), + Event.countDocuments(eventsQuery), + ]); + } catch (err) { + console.log("Events failed to be found or count at list-events"); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + + return res.status(200).json({ + page: page + 1, + lastPage, + pageLimit, + total, + sortBy, + results: events, + }); +}; diff --git a/src/routes/events/validations.js b/src/routes/events/validations.js index 2b15620..15b98be 100644 --- a/src/routes/events/validations.js +++ b/src/routes/events/validations.js @@ -1,490 +1,466 @@ -const { isEmpty } = require('lodash'); -const { isInt, isMongoId } = require('validator'); -const moment = require('moment'); - -const { isNumber } = require('../../helpers'); - -module.exports = { - validateCreateEvent(data) { - const errors = {}; - - if (typeof data.address === 'undefined' || data.address === '') { - errors.address = 'Is required'; - } else if (typeof data.address !== 'string') { - errors.address = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (data.donationEnabled === true) { - if (typeof data.donationAmounts === 'undefined') { - errors.donationAmounts = 'Is required'; - } - if (typeof data.donationGoal === 'undefined') { - errors.donationGoal = 'Is required'; - } - } - - if (typeof data.donationAmounts !== 'undefined') { - if (!Array.isArray(data.donationAmounts)) { - errors.donationAmounts = 'Should be an array'; - } else { - data.donationAmounts.some(d => { - if (typeof d.value === 'undefined') { - errors.donationAmounts = - 'All elements should have a value property'; - return true; - } else if (typeof d.value !== 'number') { - errors.donationAmounts = 'All value properties should be numbers'; - return true; - } else if (d < 5 || d > 10000) { - errors.donationAmounts = - 'All value properties should be between 5 and 10000'; - return true; - } - }); - } - } - - if ( - typeof data.donationEnabled !== 'undefined' && - typeof data.donationEnabled !== 'boolean' - ) { - errors.donationEnabled = 'Should be a boolean'; - } - - if (typeof data.donationGoal !== 'undefined') { - if (typeof data.donationGoal !== 'number') { - errors.donationGoal = 'Should be a number'; - } else if (!isInt(data.donationGoal.toString())) { - errors.donationGoal = 'Should be a integer'; - } - } - - let endDateIsValid = false; - if (typeof data.endDate === 'undefined' || data.endDate === '') { - errors.endDate = 'Is required'; - } else if (typeof data.endDate !== 'string') { - errors.endDate = 'Should be a string'; - } else if (!moment(data.endDate).isValid()) { - errors.endDate = 'Should have a ISO-8601 format'; - } else { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (endDate.isBefore(today)) { - errors.endDate = 'Should be greater than or equal to today'; - } else { - endDateIsValid = true; - } - } - - if ( - typeof data.isOpen !== 'undefined' && - typeof data.isOpen !== 'boolean' - ) { - errors.isOpen = 'Should be a boolean'; - } - - if (typeof data.locationCoordinates === 'undefined') { - errors.locationCoordinates = 'Is required'; - } else if (!Array.isArray(data.locationCoordinates)) { - errors.locationCoordinates = 'Should be an array'; - } else if (typeof data.locationCoordinates[0] === 'undefined') { - errors.locationCoordinates = 'Latitude is required'; - } else if (!isNumber(data.locationCoordinates[0])) { - errors.locationCoordinates = 'Latitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[0]) < -90 || - parseFloat(data.locationCoordinates[0]) > 90 - ) { - errors.locationCoordinates = 'Latitude value is not valid'; - } else if (typeof data.locationCoordinates[1] === 'undefined') { - errors.locationCoordinates = 'Longitude is required'; - } else if (!isNumber(data.locationCoordinates[1])) { - errors.locationCoordinates = 'Longitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[1]) < -180 || - parseFloat(data.locationCoordinates[1]) > 180 - ) { - errors.locationCoordinates = 'Longitude value is not valid'; - } else if (data.locationCoordinates.length > 2) { - errors.locationCoordinates = 'Should only have latitude and longitude'; - } - - if (typeof data.name === 'undefined' || data.name === '') { - errors.name = 'Is required'; - } else if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } - - if (typeof data.participantsGoal === 'undefined') { - errors.participantsGoal = 'Is required'; - } else if (typeof data.participantsGoal !== 'number') { - errors.participantsGoal = 'Should be a number'; - } else if (!isInt(data.participantsGoal.toString())) { - errors.participantsGoal = 'Should be a integer'; - } - - if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { - errors.poster = 'Should be a string'; - } - - if (typeof data.reviewsGoal === 'undefined') { - errors.reviewsGoal = 'Is required'; - } else if (typeof data.reviewsGoal !== 'number') { - errors.reviewsGoal = 'Should be a number'; - } else if (!isInt(data.reviewsGoal.toString())) { - errors.reviewsGoal = 'Should be a integer'; - } - - let startDateIsValid = false; - if (typeof data.startDate === 'undefined' || data.startDate === '') { - errors.startDate = 'Is required'; - } else if (typeof data.startDate !== 'string') { - errors.startDate = 'Should be a string'; - } else if (!moment(data.startDate).isValid()) { - errors.startDate = 'Should have a ISO-8601 format'; - } else { - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (startDate.isBefore(today)) { - errors.startDate = 'Should be greater than or equal to today'; - } else { - startDateIsValid = true; - } - } - - if ( - typeof data.teamManager !== 'undefined' && - typeof data.teamManager !== 'string' - ) { - errors.teamManager = 'Should be a string'; - } else if (data.teamManager && !isMongoId(data.teamManager)) { - errors.teamManager = 'Should be a valid id'; - } - - if (endDateIsValid && startDateIsValid) { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - - if (startDate.isAfter(endDate)) { - errors.endDate = 'Should be greater than or equal to startDate'; - errors.startDate = 'Should be less than or equal to endDate'; - } else if (endDate.diff(startDate, 'days') > 365) { - errors.endDate = 'Should last less than 365 days'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditEvent(data) { - const errors = {}; - - if (typeof data.address !== 'undefined') { - if (typeof data.address !== 'string') { - errors.address = 'Should be a string'; - } else if (data.address === '') { - errors.address = 'Is required'; - } - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - let endDateIsValid = false; - if (typeof data.endDate !== 'undefined') { - if (typeof data.endDate !== 'string') { - errors.endDate = 'Should be a string'; - } else if (data.endDate === '') { - errors.endDate = 'Is required'; - } else if (!moment(data.endDate).isValid()) { - errors.endDate = 'Should have a ISO-8601 format'; - } else { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (endDate.isBefore(today)) { - errors.endDate = 'Should be greater than or equal to today'; - } else { - endDateIsValid = true; - } - } - } - - if ( - typeof data.isOpen !== 'undefined' && - typeof data.isOpen !== 'boolean' - ) { - errors.isOpen = 'Should be a boolean'; - } - - if (typeof data.locationCoordinates !== 'undefined') { - if (!Array.isArray(data.locationCoordinates)) { - errors.locationCoordinates = 'Should be an array'; - } else if (typeof data.locationCoordinates[0] === 'undefined') { - errors.locationCoordinates = 'Latitude is required'; - } else if (!isNumber(data.locationCoordinates[0])) { - errors.locationCoordinates = 'Latitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[0]) < -90 || - parseFloat(data.locationCoordinates[0]) > 90 - ) { - errors.locationCoordinates = 'Latitude value is not valid'; - } else if (typeof data.locationCoordinates[1] === 'undefined') { - errors.locationCoordinates = 'Longitude is required'; - } else if (!isNumber(data.locationCoordinates[1])) { - errors.locationCoordinates = 'Longitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[1]) < -180 || - parseFloat(data.locationCoordinates[1]) > 180 - ) { - errors.locationCoordinates = 'Longitude value is not valid'; - } else if (data.locationCoordinates.length > 2) { - errors.locationCoordinates = 'Should only have latitude and longitude'; - } - } - - if (typeof data.managers !== 'undefined') { - if (!Array.isArray(data.managers)) { - errors.managers = 'Should be an array'; - } else { - data.managers.some(m => { - if (typeof m !== 'string') { - errors.managers = 'Should only have string values'; - return true; - } else if (!m) { - errors.managers = 'Should not have empty values'; - return true; - } else { - if (m.startsWith('-')) { - m = m.substring(1); - } - - if (!isMongoId(m)) { - errors.managers = `${m} should be an id`; - return true; - } - } - }); - } - } - - if (typeof data.name !== 'undefined') { - if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } else if (data.name === '') { - errors.name = 'Is required'; - } - } - - if (typeof data.participants !== 'undefined') { - if (!Array.isArray(data.participants)) { - errors.participants = 'Should be an array'; - } else { - data.participants.some(p => { - if (typeof p !== 'string') { - errors.participants = 'Should only have string values'; - return true; - } else if (!p) { - errors.participants = 'Should not have empty values'; - return true; - } else if (!p.startsWith('-')) { - errors.participants = `${p} should start with -`; - return true; - } else if (!isMongoId(p.substring(1))) { - errors.participants = `${p} should be an id`; - return true; - } - }); - } - } - - if (typeof data.participantsGoal !== 'undefined') { - if (data.participantsGoal === null) { - errors.participantsGoal = 'Is required'; - } else if (typeof data.participantsGoal !== 'number') { - errors.participantsGoal = 'Should be a number'; - } else if (!isInt(data.participantsGoal.toString())) { - errors.participantsGoal = 'Should be a integer'; - } - } - - if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { - errors.poster = 'Should be a string'; - } - - if (typeof data.reviewsGoal !== 'undefined') { - if (data.reviewsGoal === null) { - errors.reviewsGoal = 'Is required'; - } else if (typeof data.reviewsGoal !== 'number') { - errors.reviewsGoal = 'Should be a number'; - } else if (!isInt(data.reviewsGoal.toString())) { - errors.reviewsGoal = 'Should be a integer'; - } - } - - let startDateIsValid = false; - if (typeof data.startDate !== 'undefined') { - if (typeof data.startDate !== 'string') { - errors.startDate = 'Should be a string'; - } else if (data.startDate === '') { - errors.startDate = 'Is required'; - } else if (!moment(data.startDate).isValid()) { - errors.startDate = 'Should have a ISO-8601 format'; - } else { - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (startDate.isBefore(today)) { - errors.startDate = 'Should be greater than or equal to today'; - } else { - startDateIsValid = true; - } - } - } - - if ( - typeof data.teamManager !== 'undefined' && - typeof data.teamManager !== 'string' - ) { - errors.teamManager = 'Should be a string'; - } else if (data.teamManager && !isMongoId(data.teamManager)) { - errors.teamManager = 'Should be a valid id'; - } - - if (typeof data.teams !== 'undefined') { - if (!Array.isArray(data.teams)) { - errors.teams = 'Should be an array'; - } else { - data.teams.some(t => { - if (typeof t !== 'string') { - errors.teams = 'Should only have string values'; - return true; - } else if (!t) { - errors.teams = 'Should not have empty values'; - return true; - } else if (!t.startsWith('-')) { - errors.teams = `${t} should start with -`; - return true; - } else if (!isMongoId(t.substring(1))) { - errors.teams = `${t} should be an id`; - return true; - } - }); - } - } - - if (endDateIsValid && startDateIsValid) { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - - if (startDate.isAfter(endDate)) { - errors.endDate = 'Should be greater than or equal to startDate'; - errors.startDate = 'Should be less than or equal to endDate'; - } else if (endDate.diff(startDate, 'days') > 365) { - errors.endDate = 'Should last less than 365 days'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListEvents(queryParams) { - const errors = {}; - - let isAfterDateValid = false; - if ( - queryParams.afterDate && - !moment(queryParams.afterDate, 'YYYY-MM-DD', true).isValid() - ) { - errors.afterDate = 'Should have YYYY-MM-DD format'; - } else { - isAfterDateValid = true; - } - - let isBeforeDateValid = false; - if ( - queryParams.beforeDate && - !moment(queryParams.beforeDate, 'YYYY-MM-DD', true).isValid() - ) { - errors.beforeDate = 'Should have YYYY-MM-DD format'; - } else { - isBeforeDateValid = true; - } - - if (isAfterDateValid && isBeforeDateValid) { - const afterDate = moment(queryParams.afterDate, 'YYYY-MM-DD').utc(); - const beforeDate = moment(queryParams.beforeDate, 'YYYY-MM-DD').utc(); - if (afterDate.isAfter(beforeDate)) { - errors.afterDate = 'Should be less than beforeDate'; - errors.beforeDate = 'Should be greater than afterDate'; - } - } - - const sortOptions = [ - 'name', - '-name', - 'reviewsAmount', - '-reviewsAmount', - 'startDate', - '-startDate' - ]; - if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { - errors.sortBy = 'Should be a valid sort'; - } - - if (queryParams.page) { - if (!isInt(queryParams.page)) { - errors.page = 'Should be a integer'; - } else if (parseInt(queryParams.page, 10) < 1) { - errors.page = 'Should be a positive integer'; - } - } - - if (queryParams.pageLimit) { - if (!isInt(queryParams.pageLimit)) { - errors.pageLimit = 'Should be a integer'; - } else if (parseInt(queryParams.pageLimit, 10) < 1) { - errors.pageLimit = 'Should be a positive integer'; - } else if (parseInt(queryParams.pageLimit, 10) > 12) { - errors.pageLimit = 'Should be less than 13'; - } - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); +const { isInt, isMongoId } = require('validator'); +const moment = require('moment'); + +const { isNumber } = require('../../helpers'); + +module.exports = { + validateCreateEvent(data) { + const errors = {}; + + if (typeof data.address === 'undefined' || data.address === '') { + errors.address = 'Is required'; + } else if (typeof data.address !== 'string') { + errors.address = 'Should be a string'; + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + if (data.donationEnabled === true) { + if (typeof data.donationAmounts === 'undefined') { + errors.donationAmounts = 'Is required'; + } + if (typeof data.donationGoal === 'undefined') { + errors.donationGoal = 'Is required'; + } + } + + if (typeof data.donationAmounts !== 'undefined') { + if (!Array.isArray(data.donationAmounts)) { + errors.donationAmounts = 'Should be an array'; + } else { + data.donationAmounts.some((d) => { + if (typeof d.value === 'undefined') { + errors.donationAmounts = + 'All elements should have a value property'; + return true; + } else if (typeof d.value !== 'number') { + errors.donationAmounts = 'All value properties should be numbers'; + return true; + } else if (d < 5 || d > 10000) { + errors.donationAmounts = + 'All value properties should be between 5 and 10000'; + return true; + } + }); + } + } + + if ( + typeof data.donationEnabled !== 'undefined' && + typeof data.donationEnabled !== 'boolean' + ) { + errors.donationEnabled = 'Should be a boolean'; + } + + if (typeof data.donationGoal !== 'undefined') { + if (typeof data.donationGoal !== 'number') { + errors.donationGoal = 'Should be a number'; + } else if (!isInt(data.donationGoal.toString())) { + errors.donationGoal = 'Should be a integer'; + } + } + + let endDateIsValid = false; + if (typeof data.endDate === 'undefined' || data.endDate === '') { + errors.endDate = 'Is required'; + } else if (typeof data.endDate !== 'string') { + errors.endDate = 'Should be a string'; + } else if (!moment(data.endDate).isValid()) { + errors.endDate = 'Should have a ISO-8601 format'; + } else { + const endDate = moment(data.endDate).endOf('day').utc(); + const today = moment().startOf('day').utc(); + + if (endDate.isBefore(today)) { + errors.endDate = 'Should be greater than or equal to today'; + } else { + endDateIsValid = true; + } + } + + if ( + typeof data.isOpen !== 'undefined' && + typeof data.isOpen !== 'boolean' + ) { + errors.isOpen = 'Should be a boolean'; + } + + if (typeof data.locationCoordinates === 'undefined') { + errors.locationCoordinates = 'Is required'; + } else if (!Array.isArray(data.locationCoordinates)) { + errors.locationCoordinates = 'Should be an array'; + } else if (typeof data.locationCoordinates[0] === 'undefined') { + errors.locationCoordinates = 'Latitude is required'; + } else if (!isNumber(data.locationCoordinates[0])) { + errors.locationCoordinates = 'Latitude should be a number'; + } else if ( + parseFloat(data.locationCoordinates[0]) < -90 || + parseFloat(data.locationCoordinates[0]) > 90 + ) { + errors.locationCoordinates = 'Latitude value is not valid'; + } else if (typeof data.locationCoordinates[1] === 'undefined') { + errors.locationCoordinates = 'Longitude is required'; + } else if (!isNumber(data.locationCoordinates[1])) { + errors.locationCoordinates = 'Longitude should be a number'; + } else if ( + parseFloat(data.locationCoordinates[1]) < -180 || + parseFloat(data.locationCoordinates[1]) > 180 + ) { + errors.locationCoordinates = 'Longitude value is not valid'; + } else if (data.locationCoordinates.length > 2) { + errors.locationCoordinates = 'Should only have latitude and longitude'; + } + + if (typeof data.name === 'undefined' || data.name === '') { + errors.name = 'Is required'; + } else if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } + + if (typeof data.participantsGoal === 'undefined') { + errors.participantsGoal = 'Is required'; + } else if (typeof data.participantsGoal !== 'number') { + errors.participantsGoal = 'Should be a number'; + } else if (!isInt(data.participantsGoal.toString())) { + errors.participantsGoal = 'Should be a integer'; + } + + if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { + errors.poster = 'Should be a string'; + } + + if (typeof data.reviewsGoal === 'undefined') { + errors.reviewsGoal = 'Is required'; + } else if (typeof data.reviewsGoal !== 'number') { + errors.reviewsGoal = 'Should be a number'; + } else if (!isInt(data.reviewsGoal.toString())) { + errors.reviewsGoal = 'Should be a integer'; + } + + let startDateIsValid = false; + if (typeof data.startDate === 'undefined' || data.startDate === '') { + errors.startDate = 'Is required'; + } else if (typeof data.startDate !== 'string') { + errors.startDate = 'Should be a string'; + } else if (!moment(data.startDate).isValid()) { + errors.startDate = 'Should have a ISO-8601 format'; + } else { + const startDate = moment(data.startDate).startOf('day').utc(); + const today = moment().startOf('day').utc(); + + if (startDate.isBefore(today)) { + errors.startDate = 'Should be greater than or equal to today'; + } else { + startDateIsValid = true; + } + } + + if ( + typeof data.teamManager !== 'undefined' && + typeof data.teamManager !== 'string' + ) { + errors.teamManager = 'Should be a string'; + } else if (data.teamManager && !isMongoId(data.teamManager)) { + errors.teamManager = 'Should be a valid id'; + } + + if (endDateIsValid && startDateIsValid) { + const endDate = moment(data.endDate).endOf('day').utc(); + const startDate = moment(data.startDate).startOf('day').utc(); + + if (startDate.isAfter(endDate)) { + errors.endDate = 'Should be greater than or equal to startDate'; + errors.startDate = 'Should be less than or equal to endDate'; + } else if (endDate.diff(startDate, 'days') > 365) { + errors.endDate = 'Should last less than 365 days'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditEvent(data) { + const errors = {}; + + if (typeof data.address !== 'undefined') { + if (typeof data.address !== 'string') { + errors.address = 'Should be a string'; + } else if (data.address === '') { + errors.address = 'Is required'; + } + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + let endDateIsValid = false; + if (typeof data.endDate !== 'undefined') { + if (typeof data.endDate !== 'string') { + errors.endDate = 'Should be a string'; + } else if (data.endDate === '') { + errors.endDate = 'Is required'; + } else if (!moment(data.endDate).isValid()) { + errors.endDate = 'Should have a ISO-8601 format'; + } else { + const endDate = moment(data.endDate).endOf('day').utc(); + const today = moment().startOf('day').utc(); + + if (endDate.isBefore(today)) { + errors.endDate = 'Should be greater than or equal to today'; + } else { + endDateIsValid = true; + } + } + } + + if ( + typeof data.isOpen !== 'undefined' && + typeof data.isOpen !== 'boolean' + ) { + errors.isOpen = 'Should be a boolean'; + } + + if (typeof data.locationCoordinates !== 'undefined') { + if (!Array.isArray(data.locationCoordinates)) { + errors.locationCoordinates = 'Should be an array'; + } else if (typeof data.locationCoordinates[0] === 'undefined') { + errors.locationCoordinates = 'Latitude is required'; + } else if (!isNumber(data.locationCoordinates[0])) { + errors.locationCoordinates = 'Latitude should be a number'; + } else if ( + parseFloat(data.locationCoordinates[0]) < -90 || + parseFloat(data.locationCoordinates[0]) > 90 + ) { + errors.locationCoordinates = 'Latitude value is not valid'; + } else if (typeof data.locationCoordinates[1] === 'undefined') { + errors.locationCoordinates = 'Longitude is required'; + } else if (!isNumber(data.locationCoordinates[1])) { + errors.locationCoordinates = 'Longitude should be a number'; + } else if ( + parseFloat(data.locationCoordinates[1]) < -180 || + parseFloat(data.locationCoordinates[1]) > 180 + ) { + errors.locationCoordinates = 'Longitude value is not valid'; + } else if (data.locationCoordinates.length > 2) { + errors.locationCoordinates = 'Should only have latitude and longitude'; + } + } + + if (typeof data.managers !== 'undefined') { + if (!Array.isArray(data.managers)) { + errors.managers = 'Should be an array'; + } else { + data.managers.some((m) => { + if (typeof m !== 'string') { + errors.managers = 'Should only have string values'; + return true; + } else if (!m) { + errors.managers = 'Should not have empty values'; + return true; + } else { + if (m.startsWith('-')) { + m = m.substring(1); + } + + if (!isMongoId(m)) { + errors.managers = `${m} should be an id`; + return true; + } + } + }); + } + } + + if (typeof data.name !== 'undefined') { + if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } else if (data.name === '') { + errors.name = 'Is required'; + } + } + + if (typeof data.participants !== 'undefined') { + if (!Array.isArray(data.participants)) { + errors.participants = 'Should be an array'; + } else { + data.participants.some((p) => { + if (typeof p !== 'string') { + errors.participants = 'Should only have string values'; + return true; + } else if (!p) { + errors.participants = 'Should not have empty values'; + return true; + } else if (!p.startsWith('-')) { + errors.participants = `${p} should start with -`; + return true; + } else if (!isMongoId(p.substring(1))) { + errors.participants = `${p} should be an id`; + return true; + } + }); + } + } + + if (typeof data.participantsGoal !== 'undefined') { + if (data.participantsGoal === null) { + errors.participantsGoal = 'Is required'; + } else if (typeof data.participantsGoal !== 'number') { + errors.participantsGoal = 'Should be a number'; + } else if (!isInt(data.participantsGoal.toString())) { + errors.participantsGoal = 'Should be a integer'; + } + } + + if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { + errors.poster = 'Should be a string'; + } + + if (typeof data.reviewsGoal !== 'undefined') { + if (data.reviewsGoal === null) { + errors.reviewsGoal = 'Is required'; + } else if (typeof data.reviewsGoal !== 'number') { + errors.reviewsGoal = 'Should be a number'; + } else if (!isInt(data.reviewsGoal.toString())) { + errors.reviewsGoal = 'Should be a integer'; + } + } + + let startDateIsValid = false; + if (typeof data.startDate !== 'undefined') { + if (typeof data.startDate !== 'string') { + errors.startDate = 'Should be a string'; + } else if (data.startDate === '') { + errors.startDate = 'Is required'; + } else if (!moment(data.startDate).isValid()) { + errors.startDate = 'Should have a ISO-8601 format'; + } else { + const startDate = moment(data.startDate).startOf('day').utc(); + const today = moment().startOf('day').utc(); + + if (startDate.isBefore(today)) { + errors.startDate = 'Should be greater than or equal to today'; + } else { + startDateIsValid = true; + } + } + } + + if ( + typeof data.teamManager !== 'undefined' && + typeof data.teamManager !== 'string' + ) { + errors.teamManager = 'Should be a string'; + } else if (data.teamManager && !isMongoId(data.teamManager)) { + errors.teamManager = 'Should be a valid id'; + } + + if (typeof data.teams !== 'undefined') { + if (!Array.isArray(data.teams)) { + errors.teams = 'Should be an array'; + } else { + data.teams.some((t) => { + if (typeof t !== 'string') { + errors.teams = 'Should only have string values'; + return true; + } else if (!t) { + errors.teams = 'Should not have empty values'; + return true; + } else if (!t.startsWith('-')) { + errors.teams = `${t} should start with -`; + return true; + } else if (!isMongoId(t.substring(1))) { + errors.teams = `${t} should be an id`; + return true; + } + }); + } + } + + if (endDateIsValid && startDateIsValid) { + const endDate = moment(data.endDate).endOf('day').utc(); + const startDate = moment(data.startDate).startOf('day').utc(); + + if (startDate.isAfter(endDate)) { + errors.endDate = 'Should be greater than or equal to startDate'; + errors.startDate = 'Should be less than or equal to endDate'; + } else if (endDate.diff(startDate, 'days') > 365) { + errors.endDate = 'Should last less than 365 days'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListEvents(queryParams) { + const errors = {}; + + let isAfterDateValid = false; + if ( + queryParams.afterDate && + !moment(queryParams.afterDate, 'YYYY-MM-DD', true).isValid() + ) { + errors.afterDate = 'Should have YYYY-MM-DD format'; + } else { + isAfterDateValid = true; + } + + let isBeforeDateValid = false; + if ( + queryParams.beforeDate && + !moment(queryParams.beforeDate, 'YYYY-MM-DD', true).isValid() + ) { + errors.beforeDate = 'Should have YYYY-MM-DD format'; + } else { + isBeforeDateValid = true; + } + + if (isAfterDateValid && isBeforeDateValid) { + const afterDate = moment(queryParams.afterDate, 'YYYY-MM-DD').utc(); + const beforeDate = moment(queryParams.beforeDate, 'YYYY-MM-DD').utc(); + if (afterDate.isAfter(beforeDate)) { + errors.afterDate = 'Should be less than beforeDate'; + errors.beforeDate = 'Should be greater than afterDate'; + } + } + + const sortOptions = [ + 'name', + '-name', + 'reviewsAmount', + '-reviewsAmount', + 'startDate', + '-startDate' + ]; + if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { + errors.sortBy = 'Should be a valid sort'; + } + + if (queryParams.page) { + if (!isInt(queryParams.page)) { + errors.page = 'Should be a integer'; + } else if (parseInt(queryParams.page, 10) < 1) { + errors.page = 'Should be a positive integer'; + } + } + + if (queryParams.pageLimit) { + if (!isInt(queryParams.pageLimit)) { + errors.pageLimit = 'Should be a integer'; + } else if (parseInt(queryParams.pageLimit, 10) < 1) { + errors.pageLimit = 'Should be a positive integer'; + } else if (parseInt(queryParams.pageLimit, 10) > 12) { + errors.pageLimit = 'Should be less than 13'; + } + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/index.js b/src/routes/index.js index 702f72e..b7e0aae 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,25 +1,25 @@ -const express = require('express'); - -const auth = require('./auth'); -const events = require('./events'); -const others = require('./others'); -const petitions = require('./petitions'); -const photos = require('./photos'); -const reviews = require('./reviews'); -const teams = require('./teams'); -const users = require('./users'); -const venues = require('./venues'); - -const router = new express.Router(); - -router.use('', others); -router.use('/auth', auth); -router.use('/events', events); -router.use('/petitions', petitions); -router.use('/photos', photos); -router.use('/reviews', reviews); -router.use('/teams', teams); -router.use('/users', users); -router.use('/venues', venues); - -module.exports = router; +const express = require('express'); + +const auth = require('./auth'); +const events = require('./events'); +const others = require('./others'); +const petitions = require('./petitions'); +const photos = require('./photos'); +const reviews = require('./reviews'); +const teams = require('./teams'); +const users = require('./users'); +const venues = require('./venues'); + +const router = new express.Router(); + +router.use('', others); +router.use('/auth', auth); +router.use('/events', events); +router.use('/petitions', petitions); +router.use('/photos', photos); +router.use('/reviews', reviews); +router.use('/teams', teams); +router.use('/users', users); +router.use('/venues', venues); + +module.exports = router; diff --git a/src/routes/others/contact.js b/src/routes/others/contact.js index 73033b7..b0b689e 100644 --- a/src/routes/others/contact.js +++ b/src/routes/others/contact.js @@ -1,37 +1,37 @@ -const { sendEmail } = require('../../helpers'); - -const { validateContact } = require('./validations'); - -module.exports = async (req, res, next) => { - const data = { - email: req.body.email, - message: req.body.message, - name: req.body.name - }; - - const { errors, isValid } = validateContact(data); - if (!isValid) return res.status(400).json(errors); - - const subject = 'Message from Contact Page'; - const htmlContent = ` -${data.message}
-Name: ${data.name}
-Email: ${data.email}
- `; - const textContent = ` - ${data.message}\n\n - Name: ${data.name}\n - Email: ${data.email} - `; - const receiversEmails = [process.env.AXSLAB_EMAIL]; - - sendEmail({ - subject, - htmlContent, - textContent, - receiversEmails - }); - - return res.status(200).json({ message: 'Success' }); -}; +const { sendEmail } = require('../../helpers'); + +const { validateContact } = require('./validations'); + +module.exports = async (req, res) => { + const data = { + email: req.body.email, + message: req.body.message, + name: req.body.name + }; + + const { errors, isValid } = validateContact(data); + if (!isValid) return res.status(400).json(errors); + + const subject = 'Message from Contact Page'; + const htmlContent = ` +${data.message}
+Name: ${data.name}
+Email: ${data.email}
+ `; + const textContent = ` + ${data.message}\n\n + Name: ${data.name}\n + Email: ${data.email} + `; + const receiversEmails = [process.env.AXSLAB_EMAIL]; + + sendEmail({ + subject, + htmlContent, + textContent, + receiversEmails + }); + + return res.status(200).json({ message: 'Success' }); +}; diff --git a/src/routes/others/index.js b/src/routes/others/index.js index 09034dc..7ad24b6 100644 --- a/src/routes/others/index.js +++ b/src/routes/others/index.js @@ -1,11 +1,11 @@ -const express = require('express'); - -const contact = require('./contact'); -const migrateScores = require('./migrate-scores'); - -const router = new express.Router(); - -router.post('/contact', contact); -router.get('/migrate-scores', migrateScores); - -module.exports = router; +const express = require('express'); + +const contact = require('./contact'); +const migrateScores = require('./migrate-scores'); + +const router = new express.Router(); + +router.post('/contact', contact); +router.get('/migrate-scores', migrateScores); + +module.exports = router; diff --git a/src/routes/others/migrate-scores.js b/src/routes/others/migrate-scores.js index 06820bb..f311206 100644 --- a/src/routes/others/migrate-scores.js +++ b/src/routes/others/migrate-scores.js @@ -2,7 +2,7 @@ const { Venue } = require('../../models/venue'); const { Review } = require('../../models/review'); const { User } = require('../../models/user'); -module.exports = async (req, res, next) => { +module.exports = async (req, res) => { const saveChanges = req.query.save && req.query.save === 'true'; console.log('IN MIGRATE SCORES, SAVING CHANGES: ' + saveChanges); @@ -28,7 +28,7 @@ module.exports = async (req, res, next) => { let venuesProcessed = 0; let pages = 0; while (venuesProcessed < venuesTotalCount) { - timeBlockStart = new Date(); + let timeBlockStart = new Date(); let venueChunk; try { venueChunk = await Venue.find({ @@ -52,8 +52,8 @@ module.exports = async (req, res, next) => { console.log('UNEXPECTED AMOUNT OF VENUES UNCONVERTED FOUND'); } - for (venue of venueChunk) { - for (review of venue.reviews) { + for (const venue of venueChunk) { + for (const review of venue.reviews) { //console.log("reviewID: ", review); let dbReview; @@ -88,6 +88,7 @@ module.exports = async (req, res, next) => { case 4: dbReview.hasWideEntrance = true; venue.hasWideEntrance.yes += 1; + break; case 3: dbReview.hasPortableRamp = true; venue.hasPortableRamp.yes += 1; @@ -111,6 +112,7 @@ module.exports = async (req, res, next) => { venue.hasLoweredSinks.yes += 1; dbReview.hasSupportAroundToilet = true; venue.hasSupportAroundToilet.yes += 1; + break; case 3: dbReview.hasSwingOutDoor = true; venue.hasSwingOutDoor.yes += 1; @@ -201,40 +203,47 @@ module.exports = async (req, res, next) => { } //end venues while-loop try { - reviewsTotalCount = await Review.countDocuments({ + // Count the total number of unconverted reviews + const reviewsTotalCount = await Review.countDocuments({ _isScoreConverted: { $ne: true } }); - } catch (err) { - console.log('Reviews unconverted failed to be counted, error: ', err); - return res.status(404).json(err); - } - console.log('THERE ARE ' + reviewsTotalCount + ' UNCONVERTED REVIEWS'); - - if (reviewsTotalCount > 0) { - let unconvertedReviews; + console.log('THERE ARE ' + reviewsTotalCount + ' UNCONVERTED REVIEWS'); - try { - unconvertedReviews = await Review.find({ - _isScoreConverted: { $ne: true } - }); - } catch (err) { - console.log('Reviews unconverted failed to be found, error: ', err); - return res.status(404).json(err); - } + if (reviewsTotalCount > 0) { + let unconvertedReviews; - for (unconvertedReview of unconvertedReviews) { try { - matchingVenue = await Venue.find({ - reviews: unconvertedReview.id + // Find all unconverted reviews + unconvertedReviews = await Review.find({ + _isScoreConverted: { $ne: true } }); } catch (err) { console.log('Reviews unconverted failed to be found, error: ', err); return res.status(404).json(err); } - console.log('Review ID: ' + unconvertedReview.id); - console.log("Review's venue: " + matchingVenue.id); + for (const unconvertedReview of unconvertedReviews) { + let matchingVenue; + + try { + // Find the venue for each unconverted review + matchingVenue = await Venue.findOne({ + reviews: unconvertedReview.id + }); + } catch (err) { + console.log('Venue search failed, error: ', err); + return res.status(404).json(err); + } + + console.log('Review ID: ' + unconvertedReview.id); + console.log( + "Review's venue: " + (matchingVenue ? matchingVenue.id : 'Not found') + ); + } } + } catch (err) { + console.log('Reviews unconverted count failed, error: ', err); + return res.status(404).json(err); } console.log('FINISHED PROCESSING ALL RECORDS'); diff --git a/src/routes/others/validations.js b/src/routes/others/validations.js index b1a8c92..3663493 100644 --- a/src/routes/others/validations.js +++ b/src/routes/others/validations.js @@ -1,37 +1,37 @@ -const freemail = require('freemail'); -const { isEmail } = require('validator'); -const { isEmpty } = require('lodash'); - -module.exports = { - validateContact(data) { - const errors = {}; - - if (typeof data.email === 'undefined' || data.email === '') { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (data.email.length > 254) { - errors.email = 'Should be less than 255 characters'; - } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { - errors.email = 'Should be a valid email'; - } - - if (typeof data.message === 'undefined' || data.message === '') { - errors.message = 'Is required'; - } else if (typeof data.message !== 'string') { - errors.message = 'Should be a string'; - } else if (data.message.length > 300) { - errors.message = 'Should be less than 301 characters'; - } - - if (typeof data.name === 'undefined' || data.name === '') { - errors.name = 'Is required'; - } else if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } else if (data.name.length > 60) { - errors.name = 'Should be less than 61 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const freemail = require('freemail'); +const { isEmail } = require('validator'); +const { isEmpty } = require('lodash'); + +module.exports = { + validateContact(data) { + const errors = {}; + + if (typeof data.email === 'undefined' || data.email === '') { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } else if (data.email.length > 254) { + errors.email = 'Should be less than 255 characters'; + } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { + errors.email = 'Should be a valid email'; + } + + if (typeof data.message === 'undefined' || data.message === '') { + errors.message = 'Is required'; + } else if (typeof data.message !== 'string') { + errors.message = 'Should be a string'; + } else if (data.message.length > 300) { + errors.message = 'Should be less than 301 characters'; + } + + if (typeof data.name === 'undefined' || data.name === '') { + errors.name = 'Is required'; + } else if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } else if (data.name.length > 60) { + errors.name = 'Should be less than 61 characters'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/petitions/create-petition.js b/src/routes/petitions/create-petition.js index 82ba6b7..3e1b5d8 100644 --- a/src/routes/petitions/create-petition.js +++ b/src/routes/petitions/create-petition.js @@ -1,474 +1,474 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateCreatePetition } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateCreatePetition(req.body); - if (!isValid) return res.status(400).json(errors); - - const data = Object.assign( - {}, - { - event: req.body.event, - message: req.body.message, - team: req.body.team, - type: req.body.type, - user: req.body.user - } - ); - data.sender = req.user.id.toString(); - const today = moment.utc(); - - if (data.type === 'invite-team-event') { - delete data.user; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - team: data.team, - type: data.type - }); - } catch (err) { - console.log( - `Petition from event ${data.event} to team ${ - data.team - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'Team already has a pending invitation to event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ event: 'Not found' }); - - if (!event.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (event.teams.find(t => t.toString() === data.team)) { - return res.status(400).json({ - general: 'Team is already participant of event' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - } else if (data.type === 'invite-user-event') { - delete data.team; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - type: data.type, - user: data.user - }); - } catch (err) { - console.log( - `Petition from event ${data.event} to user ${ - data.user - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already has a pending invitation to event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - if (data.sender === data.user) { - return res.status(400).json({ general: 'User should not be you' }); - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ general: 'Event not found' }); - - if (!event.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (event.participants.find(p => p.toString() === data.user)) { - return res.status(400).json({ - general: 'User is already participant of event' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - - let user; - try { - user = await User.findOne({ _id: data.user }); - } catch (err) { - console.log(`User ${data.user} failed to be found at create-petition`); - return next(err); - } - - if (!user) return res.status(404).json({ general: 'User not found' }); - } else if (data.type === 'invite-user-team') { - delete data.event; - - let petition; - try { - petition = await Petition.findOne({ - team: data.team, - type: data.type, - user: data.user - }); - } catch (err) { - console.log( - `Petition from team ${data.team} to user ${ - data.user - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already has a pending invitation to team' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - if (req.sender === data.user) { - return res.status(400).json({ general: 'User should not be you' }); - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - - if (!team.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (team.members.find(m => m.toString() === data.user)) { - return res.status(400).json({ - general: 'User is already member of team' - }); - } - - let user; - try { - user = await User.findOne({ _id: data.user }); - } catch (err) { - console.log(`User ${data.user} failed to be found at create-petition`); - return next(err); - } - - if (!user) return res.status(404).json({ general: 'User not found' }); - } else if (data.type === 'request-team-event') { - delete data.user; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - team: data.team, - type: data.type - }); - } catch (err) { - console.log( - `Petition from team ${data.team} to event ${ - data.event - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'Team already has a pending request with event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ general: 'Event not found' }); - - if (event.teams.find(t => t.toString() === data.sender)) { - return res.status(400).json({ - general: 'Team is already participant of event ' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - - if (!team.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else if (data.type === 'request-user-event') { - delete data.team; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - sender: data.sender, - type: data.type - }); - } catch (err) { - console.log( - `Petition from user ${data.sender} to event ${ - data.event - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already have a pending request with event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ general: 'Event not found' }); - - if (event.participants.find(p => p.toString() === data.sender)) { - return res.status(400).json({ - general: 'User already is participant of event' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - } else { - // data.type === request-user-team - delete data.event; - - let petition; - try { - petition = await Petition.findOne({ - team: data.team, - sender: data.sender, - type: data.type - }); - } catch (err) { - console.log( - `Petition from user ${data.sender} to team ${ - data.team - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already have a pending request with team' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - - if (team.members.find(m => m.toString() === data.sender)) { - return res.status(400).json({ - general: 'User already is member of team' - }); - } - } - - let petition; - try { - petition = await Petition.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Petition failed to be created at create-petition.\nData: ${JSON.stringify( - data - )}` - ); - return next(err); - } - - const dataResponse = Object.assign( - {}, - { - createdAt: petition.createdAt, - event: petition.event, - message: petition.message, - sender: petition.sender, - state: petition.state, - team: petition.team, - type: petition.type, - user: petition.user - } - ); - return res.status(201).json(dataResponse); -}; +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Petition } = require('../../models/petition'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const { validateCreatePetition } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateCreatePetition(req.body); + if (!isValid) return res.status(400).json(errors); + + const data = Object.assign( + {}, + { + event: req.body.event, + message: req.body.message, + team: req.body.team, + type: req.body.type, + user: req.body.user + } + ); + data.sender = req.user.id.toString(); + const today = moment.utc(); + + if (data.type === 'invite-team-event') { + delete data.user; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + team: data.team, + type: data.type + }); + } catch (err) { + console.log( + `Petition from event ${data.event} to team ${ + data.team + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'Team already has a pending invitation to event' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ event: 'Not found' }); + + if (!event.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (event.teams.find((t) => t.toString() === data.team)) { + return res.status(400).json({ + general: 'Team is already participant of event' + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: 'Event has already finished' }); + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: 'Team not found' }); + } else if (data.type === 'invite-user-event') { + delete data.team; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + type: data.type, + user: data.user + }); + } catch (err) { + console.log( + `Petition from event ${data.event} to user ${ + data.user + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'User already has a pending invitation to event' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + if (data.sender === data.user) { + return res.status(400).json({ general: 'User should not be you' }); + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ general: 'Event not found' }); + + if (!event.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (event.participants.find((p) => p.toString() === data.user)) { + return res.status(400).json({ + general: 'User is already participant of event' + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: 'Event has already finished' }); + } + + let user; + try { + user = await User.findOne({ _id: data.user }); + } catch (err) { + console.log(`User ${data.user} failed to be found at create-petition`); + return next(err); + } + + if (!user) return res.status(404).json({ general: 'User not found' }); + } else if (data.type === 'invite-user-team') { + delete data.event; + + let petition; + try { + petition = await Petition.findOne({ + team: data.team, + type: data.type, + user: data.user + }); + } catch (err) { + console.log( + `Petition from team ${data.team} to user ${ + data.user + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'User already has a pending invitation to team' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + if (req.sender === data.user) { + return res.status(400).json({ general: 'User should not be you' }); + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: 'Team not found' }); + + if (!team.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (team.members.find((m) => m.toString() === data.user)) { + return res.status(400).json({ + general: 'User is already member of team' + }); + } + + let user; + try { + user = await User.findOne({ _id: data.user }); + } catch (err) { + console.log(`User ${data.user} failed to be found at create-petition`); + return next(err); + } + + if (!user) return res.status(404).json({ general: 'User not found' }); + } else if (data.type === 'request-team-event') { + delete data.user; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + team: data.team, + type: data.type + }); + } catch (err) { + console.log( + `Petition from team ${data.team} to event ${ + data.event + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'Team already has a pending request with event' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ general: 'Event not found' }); + + if (event.teams.find((t) => t.toString() === data.sender)) { + return res.status(400).json({ + general: 'Team is already participant of event ' + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: 'Event has already finished' }); + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: 'Team not found' }); + + if (!team.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else if (data.type === 'request-user-event') { + delete data.team; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + sender: data.sender, + type: data.type + }); + } catch (err) { + console.log( + `Petition from user ${data.sender} to event ${ + data.event + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'User already have a pending request with event' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ general: 'Event not found' }); + + if (event.participants.find((p) => p.toString() === data.sender)) { + return res.status(400).json({ + general: 'User already is participant of event' + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: 'Event has already finished' }); + } + } else { + // data.type === request-user-team + delete data.event; + + let petition; + try { + petition = await Petition.findOne({ + team: data.team, + sender: data.sender, + type: data.type + }); + } catch (err) { + console.log( + `Petition from user ${data.sender} to team ${ + data.team + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'User already have a pending request with team' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: 'Team not found' }); + + if (team.members.find((m) => m.toString() === data.sender)) { + return res.status(400).json({ + general: 'User already is member of team' + }); + } + } + + let petition; + try { + petition = await Petition.create(data); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Petition failed to be created at create-petition.\nData: ${JSON.stringify( + data + )}` + ); + return next(err); + } + + const dataResponse = Object.assign( + {}, + { + createdAt: petition.createdAt, + event: petition.event, + message: petition.message, + sender: petition.sender, + state: petition.state, + team: petition.team, + type: petition.type, + user: petition.user + } + ); + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/petitions/edit-petition.js b/src/routes/petitions/edit-petition.js index 5537b38..b3adcfa 100644 --- a/src/routes/petitions/edit-petition.js +++ b/src/routes/petitions/edit-petition.js @@ -1,555 +1,557 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateEditPetition } = require('./validations'); - -module.exports = async (req, res, next) => { - const petitionId = req.params.petitionId; - - let petition; - try { - petition = await Petition.findOne({ _id: petitionId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Petition not found' }); - } - - console.log(`Petition ${petitionId} failed to be found at edit-petition`); - return next(err); - } - - if (!petition) { - return res.status(404).json({ general: 'Petition not found' }); - } - - if (petition.state === 'accepted') { - return res.status(400).json({ general: 'Is already accepted' }); - } - - if (petition.state === 'canceled') { - return res.status(400).json({ general: 'Is already canceled' }); - } - - if (petition.state === 'rejected') { - return res.status(400).json({ general: 'Is already rejected' }); - } - - const { errors, isValid } = validateEditPetition(req.body); - if (!isValid) return res.status(400).json(errors); - - let isSender = false; - - if (petition.sender.toString() === req.user.id) { - isSender = true; - if (req.body.state === 'canceled') { - petition.state = 'canceled'; - } else { - return res.status(400).json({ state: 'Should only be canceled' }); - } - } - - if (petition.type.endsWith('event')) { - let event; - try { - event = await Event.findOne({ _id: petition.event }); - } catch (err) { - console.log( - `Event ${petition.event} failed to be found at edit-petition` - ); - return next(err); - } - - if (!event) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Event is already removed. Petition was removed' - }); - } - - if (petition.type === 'invite-team-event') { - let team; - try { - team = await Team.findOne({ _id: petition.team }); - } catch (err) { - console.log( - `Team ${petition.team} failed to be found at edit-petition` - ); - return next(err); - } - - if (!team) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Team is already removed. Petition was removed' - }); - } - - if (event.teams.find(t => t.toString() === team.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'Team is already a participant of event. Petition was removed' - }); - } - - if (isSender) { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.teams = [...event.teams, team.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - team.events = [...team.events, event.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else if (petition.type === 'invite-user-event') { - if ( - event.participants.find(p => p.toString() === petition.user.toString()) - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'User is already a participant of event. Petition was removed' - }); - } - - if (isSender) { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (petition.user.toString() !== req.user.id) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.participants = [...event.participants, req.user.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - req.user.events = [...req.user.events, event.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log( - `User ${req.user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else if (petition.type === 'request-team-event') { - let team; - try { - team = await Team.findOne({ _id: petition.team }); - } catch (err) { - console.log( - `Team ${petition.team} failed to be found at edit-petition` - ); - return next(err); - } - - if (!team) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Team is already removed. Petition was removed' - }); - } - - if (event.teams.find(t => t.toString() === team.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'Team is already a participant of event. Petition was removed' - }); - } - - if (isSender) { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.teams = [...event.teams, team.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - team.events = [...team.events, event.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else { - // petition.type === 'request-user-event' - let user; - try { - user = await User.findOne({ _id: petition.sender }); - } catch (err) { - console.log( - `User ${petition.user} failed to be found at edit-petition` - ); - return next(err); - } - - if (!user) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already removed. Petition was removed' - }); - } - - if (event.participants.find(p => p.toString() === user.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'User is already a participant of event. Petition was removed' - }); - } - - if (!isSender) { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.participants = [...event.participants, user.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - user.events = [...user.events, event.id]; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User ${user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } - } else { - // petition.type.endsWith('team') - let team; - try { - team = await Team.findOne({ _id: petition.team }); - } catch (err) { - console.log( - `Team ${petition.entityId} failed to be found at edit-petition` - ); - return next(err); - } - - if (!team) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Team is already removed. Petition was removed' - }); - } - - if (petition.type === 'invite-user-team') { - if (team.members.find(m => m.toString() === petition.user.toString())) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already a member of team. Petition was removed' - }); - } - - if (isSender) { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (petition.user.toString() !== req.user.id) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - team.members = [...team.members, req.user.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - req.user.teams = [...req.user.teams, team.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log( - `User ${req.user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else { - // petition.type === 'request-user-team' - - let user; - try { - user = await User.findOne({ _id: petition.sender }); - } catch (err) { - console.log( - `User ${petition.senderId} failed to be found at edit-petition` - ); - return next(err); - } - - if (!user) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already removed. Petition was removed' - }); - } - - if (team.members.find(m => m.toString() === user.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already a member of team. Petition was removed' - }); - } - - if (!isSender) { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - team.members = [...team.members, user.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - user.teams = [...user.teams, team.id]; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User ${user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } - } - - petition.updatedAt = moment.utc().toDate(); - - try { - await petition.save(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be updated at edit-petition` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Petition } = require('../../models/petition'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const { validateEditPetition } = require('./validations'); + +module.exports = async (req, res, next) => { + const petitionId = req.params.petitionId; + + let petition; + try { + petition = await Petition.findOne({ _id: petitionId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Petition not found' }); + } + + console.log(`Petition ${petitionId} failed to be found at edit-petition`); + return next(err); + } + + if (!petition) { + return res.status(404).json({ general: 'Petition not found' }); + } + + if (petition.state === 'accepted') { + return res.status(400).json({ general: 'Is already accepted' }); + } + + if (petition.state === 'canceled') { + return res.status(400).json({ general: 'Is already canceled' }); + } + + if (petition.state === 'rejected') { + return res.status(400).json({ general: 'Is already rejected' }); + } + + const { errors, isValid } = validateEditPetition(req.body); + if (!isValid) return res.status(400).json(errors); + + let isSender = false; + + if (petition.sender.toString() === req.user.id) { + isSender = true; + if (req.body.state === 'canceled') { + petition.state = 'canceled'; + } else { + return res.status(400).json({ state: 'Should only be canceled' }); + } + } + + if (petition.type.endsWith('event')) { + let event; + try { + event = await Event.findOne({ _id: petition.event }); + } catch (err) { + console.log( + `Event ${petition.event} failed to be found at edit-petition` + ); + return next(err); + } + + if (!event) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'Event is already removed. Petition was removed' + }); + } + + if (petition.type === 'invite-team-event') { + let team; + try { + team = await Team.findOne({ _id: petition.team }); + } catch (err) { + console.log( + `Team ${petition.team} failed to be found at edit-petition` + ); + return next(err); + } + + if (!team) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'Team is already removed. Petition was removed' + }); + } + + if (event.teams.find((t) => t.toString() === team.id)) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + 'Team is already a participant of event. Petition was removed' + }); + } + + if (isSender) { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + event.teams = [...event.teams, team.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + team.events = [...team.events, event.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } else if (petition.type === 'invite-user-event') { + if ( + event.participants.find( + (p) => p.toString() === petition.user.toString() + ) + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + 'User is already a participant of event. Petition was removed' + }); + } + + if (isSender) { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else { + if (petition.user.toString() !== req.user.id) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + event.participants = [...event.participants, req.user.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + req.user.events = [...req.user.events, event.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log( + `User ${req.user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } else if (petition.type === 'request-team-event') { + let team; + try { + team = await Team.findOne({ _id: petition.team }); + } catch (err) { + console.log( + `Team ${petition.team} failed to be found at edit-petition` + ); + return next(err); + } + + if (!team) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'Team is already removed. Petition was removed' + }); + } + + if (event.teams.find((t) => t.toString() === team.id)) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + 'Team is already a participant of event. Petition was removed' + }); + } + + if (isSender) { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + event.teams = [...event.teams, team.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + team.events = [...team.events, event.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } else { + // petition.type === 'request-user-event' + let user; + try { + user = await User.findOne({ _id: petition.sender }); + } catch (err) { + console.log( + `User ${petition.user} failed to be found at edit-petition` + ); + return next(err); + } + + if (!user) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'User is already removed. Petition was removed' + }); + } + + if (event.participants.find((p) => p.toString() === user.id)) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + 'User is already a participant of event. Petition was removed' + }); + } + + if (!isSender) { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + event.participants = [...event.participants, user.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + user.events = [...user.events, event.id]; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User ${user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } + } else { + // petition.type.endsWith('team') + let team; + try { + team = await Team.findOne({ _id: petition.team }); + } catch (err) { + console.log( + `Team ${petition.entityId} failed to be found at edit-petition` + ); + return next(err); + } + + if (!team) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'Team is already removed. Petition was removed' + }); + } + + if (petition.type === 'invite-user-team') { + if (team.members.find((m) => m.toString() === petition.user.toString())) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'User is already a member of team. Petition was removed' + }); + } + + if (isSender) { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else { + if (petition.user.toString() !== req.user.id) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + team.members = [...team.members, req.user.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + req.user.teams = [...req.user.teams, team.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log( + `User ${req.user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } else { + // petition.type === 'request-user-team' + + let user; + try { + user = await User.findOne({ _id: petition.sender }); + } catch (err) { + console.log( + `User ${petition.senderId} failed to be found at edit-petition` + ); + return next(err); + } + + if (!user) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'User is already removed. Petition was removed' + }); + } + + if (team.members.find((m) => m.toString() === user.id)) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'User is already a member of team. Petition was removed' + }); + } + + if (!isSender) { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + team.members = [...team.members, user.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + user.teams = [...user.teams, team.id]; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User ${user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } + } + + petition.updatedAt = moment.utc().toDate(); + + try { + await petition.save(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be updated at edit-petition` + ); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/petitions/index.js b/src/routes/petitions/index.js index c2de682..fb87cfe 100644 --- a/src/routes/petitions/index.js +++ b/src/routes/petitions/index.js @@ -1,19 +1,19 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createPetition = require('./create-petition'); -const editPetition = require('./edit-petition'); -const listPetitions = require('./list-petitions'); - -const router = new express.Router(); - -router.get('', isAuthenticated({ isOptional: false }), listPetitions); -router.post('', isAuthenticated({ isOptional: false }), createPetition); -router.put( - '/:petitionId', - isAuthenticated({ isOptional: false }), - editPetition -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const createPetition = require('./create-petition'); +const editPetition = require('./edit-petition'); +const listPetitions = require('./list-petitions'); + +const router = new express.Router(); + +router.get('', isAuthenticated({ isOptional: false }), listPetitions); +router.post('', isAuthenticated({ isOptional: false }), createPetition); +router.put( + '/:petitionId', + isAuthenticated({ isOptional: false }), + editPetition +); + +module.exports = router; diff --git a/src/routes/petitions/list-petitions.js b/src/routes/petitions/list-petitions.js index 838d0cb..5188a62 100644 --- a/src/routes/petitions/list-petitions.js +++ b/src/routes/petitions/list-petitions.js @@ -1,277 +1,277 @@ -const mongoose = require('mongoose'); - -const { compact } = require('lodash'); -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); -const { Event } = require('../../models/event'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - const userId = mongoose.Types.ObjectId(req.user.id); - - const petitionsQuery = { - state: { $in: ['accepted', 'pending', 'rejected'] } - }; - - if (queryParams.filter === 'sent') { - petitionsQuery.sender = userId; - } else { - // get the user's events - const getUserEvents = req.user.events.map(e => Event.findOne({ _id: e })); - // get the user's teams - const getUserTeams = req.user.teams.map(t => Team.findOne({ _id: t })); - - let userEvents = []; - let userTeams = []; - try { - userEvents = await Promise.all(getUserEvents); - // remove null values from array - userEvents = compact(userEvents); - userTeams = await Promise.all(getUserTeams); - // remove null values from array - userTeams = compact(userTeams); - } catch (err) { - console.log('Events/Teams failed to be found at list-petitions'); - return next(err); - } - - const managedEvents = []; - userEvents.map(e => { - const eventManagers = e.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - managedEvents.push(mongoose.Types.ObjectId(e.id)); - } - }); - - const managedTeams = []; - userTeams.map(t => { - const teamManagers = t.managers.map(m => m.toString()); - if (teamManagers.includes(req.user.id)) { - managedTeams.push(mongoose.Types.ObjectId(t.id)); - } - }); - - petitionsQuery.$or = [ - { - $and: [ - { user: userId }, - { type: { $in: ['invite-user-event', 'invite-user-team'] } } - ] - }, - { - $and: [ - { event: { $in: managedEvents } }, - { type: { $in: ['request-team-event', 'request-user-event'] } } - ] - }, - { - $and: [ - { team: { $in: managedTeams } }, - { type: { $in: ['invite-team-event', 'request-user-team'] } } - ] - } - ]; - } - - const sortBy = '-createdAt'; - - let page = queryParams.page || 1; - const pageLimit = 12; - if (page > 0) { - page -= 1; - } else { - return res - .status(400) - .json({ page: 'Should be equal to or greater than 1' }); - } - - // Fetch data - const aggregateQuery = [ - { - $match: petitionsQuery - }, - { - $sort: { createdAt: -1 } - }, - { - $lookup: { - from: 'events', - let: { event: '$event' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$event'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - name: 1, - poster: 1 - } - } - ], - as: 'event' - } - }, - { - $unwind: { - path: '$event', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'users', - let: { sender: '$sender' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$sender'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'sender' - } - }, - { - $unwind: { - path: '$sender', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'teams', - let: { team: '$team' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$team'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'team' - } - }, - { - $unwind: { - path: '$team', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'users', - let: { user: '$user' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$user'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'user' - } - }, - { - $unwind: { - path: '$user', - preserveNullAndEmptyArrays: true - } - }, - { - $project: { - _id: 0, - id: '$_id', - createdAt: 1, - event: 1, - message: 1, - sender: 1, - state: 1, - team: 1, - type: 1, - user: 1 - } - } - ]; - - // paginate - aggregateQuery.push( - { - $skip: page * pageLimit - }, - { - $limit: pageLimit - } - ); - - let petitions; - let total; - try { - [petitions, total] = await Promise.all([ - Petition.aggregate(aggregateQuery), - Petition.find(petitionsQuery).count() - ]); - } catch (err) { - console.log('Petitions failed to be found or count at list-petitions'); - return next(err); - } - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - page += 1; - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - return res.status(200).json({ - page, - lastPage, - pageLimit, - total, - sortBy, - results: petitions - }); -}; +const mongoose = require('mongoose'); + +const { compact } = require('lodash'); +const { Petition } = require('../../models/petition'); +const { Team } = require('../../models/team'); +const { Event } = require('../../models/event'); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + const userId = new mongoose.Types.ObjectId(req.user.id); + + const petitionsQuery = { + state: { $in: ['accepted', 'pending', 'rejected'] } + }; + + if (queryParams.filter === 'sent') { + petitionsQuery.sender = userId; + } else { + // get the user's events + const getUserEvents = req.user.events.map((e) => Event.findOne({ _id: e })); + // get the user's teams + const getUserTeams = req.user.teams.map((t) => Team.findOne({ _id: t })); + + let userEvents = []; + let userTeams = []; + try { + userEvents = await Promise.all(getUserEvents); + // remove null values from array + userEvents = compact(userEvents); + userTeams = await Promise.all(getUserTeams); + // remove null values from array + userTeams = compact(userTeams); + } catch (err) { + console.log('Events/Teams failed to be found at list-petitions'); + return next(err); + } + + const managedEvents = []; + userEvents.map((e) => { + const eventManagers = e.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + managedEvents.push(new mongoose.Types.ObjectId(e.id)); + } + }); + + const managedTeams = []; + userTeams.map((t) => { + const teamManagers = t.managers.map((m) => m.toString()); + if (teamManagers.includes(req.user.id)) { + managedTeams.push(new mongoose.Types.ObjectId(t.id)); + } + }); + + petitionsQuery.$or = [ + { + $and: [ + { user: userId }, + { type: { $in: ['invite-user-event', 'invite-user-team'] } } + ] + }, + { + $and: [ + { event: { $in: managedEvents } }, + { type: { $in: ['request-team-event', 'request-user-event'] } } + ] + }, + { + $and: [ + { team: { $in: managedTeams } }, + { type: { $in: ['invite-team-event', 'request-user-team'] } } + ] + } + ]; + } + + const sortBy = '-createdAt'; + + let page = queryParams.page || 1; + const pageLimit = 12; + if (page > 0) { + page -= 1; + } else { + return res + .status(400) + .json({ page: 'Should be equal to or greater than 1' }); + } + + // Fetch data + const aggregateQuery = [ + { + $match: petitionsQuery + }, + { + $sort: { createdAt: -1 } + }, + { + $lookup: { + from: 'events', + let: { event: '$event' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$event'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + name: 1, + poster: 1 + } + } + ], + as: 'event' + } + }, + { + $unwind: { + path: '$event', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'users', + let: { sender: '$sender' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$sender'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'sender' + } + }, + { + $unwind: { + path: '$sender', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'teams', + let: { team: '$team' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$team'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + name: 1 + } + } + ], + as: 'team' + } + }, + { + $unwind: { + path: '$team', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'users', + let: { user: '$user' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$user'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'user' + } + }, + { + $unwind: { + path: '$user', + preserveNullAndEmptyArrays: true + } + }, + { + $project: { + _id: 0, + id: '$_id', + createdAt: 1, + event: 1, + message: 1, + sender: 1, + state: 1, + team: 1, + type: 1, + user: 1 + } + } + ]; + + // paginate + aggregateQuery.push( + { + $skip: page * pageLimit + }, + { + $limit: pageLimit + } + ); + + let petitions; + let total; + try { + [petitions, total] = await Promise.all([ + Petition.aggregate(aggregateQuery), + Petition.countDocuments(petitionsQuery) + ]); + } catch (err) { + console.log('Petitions failed to be found or count at list-petitions'); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + page += 1; + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + + return res.status(200).json({ + page, + lastPage, + pageLimit, + total, + sortBy, + results: petitions + }); +}; diff --git a/src/routes/petitions/validations.js b/src/routes/petitions/validations.js index fe683d3..03d0f2b 100644 --- a/src/routes/petitions/validations.js +++ b/src/routes/petitions/validations.js @@ -1,79 +1,79 @@ -const { isEmpty } = require('lodash'); -const { isMongoId } = require('validator'); - -const { Petition } = require('../../models/petition'); - -module.exports = { - validateCreatePetition(data) { - const errors = {}; - - if (data.event) { - if (typeof data.event !== 'string') { - errors.event = 'Should be a string'; - } else if (!isMongoId(data.event)) { - errors.event = 'Should be a valid id'; - } - } - - if (data.message && typeof data.message !== 'string') { - errors.message = 'Should be a string'; - } - - if (data.team) { - if (typeof data.team !== 'string') { - errors.team = 'Should be a string'; - } else if (!isMongoId(data.team)) { - errors.team = 'Should be a valid id'; - } - } - - const petitionTypes = Petition.schema.path('type').enumValues; - if (!data.type) { - errors.type = 'Is required'; - } else if (typeof data.type !== 'string') { - errors.type = 'Should be a string'; - } else if (!petitionTypes.includes(data.type)) { - errors.type = 'Should be a valid type'; - } else if ( - data.type === 'invite-team-event' || - data.type === 'request-team-event' - ) { - if (!data.event) errors.event = 'Is required'; - if (!data.team) errors.team = 'Is required'; - } else if (data.type === 'invite-user-event') { - if (!data.event) errors.event = 'Is required'; - if (!data.user) errors.user = 'Is required'; - } else if (data.type === 'request-user-event' && !data.event) { - errors.event = 'Is required'; - } else if (data.type === 'invite-user-team') { - if (!data.team) errors.team = 'Is required'; - if (!data.user) errors.user = 'Is required'; - } else if (data.type === 'request-user-team' && !data.team) { - errors.team = 'Is required'; - } - - if (data.user) { - if (typeof data.user !== 'string') { - errors.user = 'Should be a string'; - } else if (!isMongoId(data.user)) { - errors.user = 'Should be a valid id'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditPetition(data) { - const errors = {}; - - const petitionStates = Petition.schema.path('state').enumValues; - if (!data.state) { - errors.state = 'Is required'; - } else if (!petitionStates.includes(data.state)) { - errors.state = 'Should be a valid state'; - } else if (data.state === 'pending') { - errors.state = 'Should be a different state'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); +const { isMongoId } = require('validator'); + +const { Petition } = require('../../models/petition'); + +module.exports = { + validateCreatePetition(data) { + const errors = {}; + + if (data.event) { + if (typeof data.event !== 'string') { + errors.event = 'Should be a string'; + } else if (!isMongoId(data.event)) { + errors.event = 'Should be a valid id'; + } + } + + if (data.message && typeof data.message !== 'string') { + errors.message = 'Should be a string'; + } + + if (data.team) { + if (typeof data.team !== 'string') { + errors.team = 'Should be a string'; + } else if (!isMongoId(data.team)) { + errors.team = 'Should be a valid id'; + } + } + + const petitionTypes = Petition.schema.path('type').enumValues; + if (!data.type) { + errors.type = 'Is required'; + } else if (typeof data.type !== 'string') { + errors.type = 'Should be a string'; + } else if (!petitionTypes.includes(data.type)) { + errors.type = 'Should be a valid type'; + } else if ( + data.type === 'invite-team-event' || + data.type === 'request-team-event' + ) { + if (!data.event) errors.event = 'Is required'; + if (!data.team) errors.team = 'Is required'; + } else if (data.type === 'invite-user-event') { + if (!data.event) errors.event = 'Is required'; + if (!data.user) errors.user = 'Is required'; + } else if (data.type === 'request-user-event' && !data.event) { + errors.event = 'Is required'; + } else if (data.type === 'invite-user-team') { + if (!data.team) errors.team = 'Is required'; + if (!data.user) errors.user = 'Is required'; + } else if (data.type === 'request-user-team' && !data.team) { + errors.team = 'Is required'; + } + + if (data.user) { + if (typeof data.user !== 'string') { + errors.user = 'Should be a string'; + } else if (!isMongoId(data.user)) { + errors.user = 'Should be a valid id'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditPetition(data) { + const errors = {}; + + const petitionStates = Petition.schema.path('state').enumValues; + if (!data.state) { + errors.state = 'Is required'; + } else if (!petitionStates.includes(data.state)) { + errors.state = 'Should be a valid state'; + } else if (data.state === 'pending') { + errors.state = 'Should be a different state'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/photos/create-photo.js b/src/routes/photos/create-photo.js index 43fd66d..8db09f7 100644 --- a/src/routes/photos/create-photo.js +++ b/src/routes/photos/create-photo.js @@ -1,115 +1,115 @@ -const fs = require('fs'); -const util = require('util'); - -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const multer = require('multer'); -const randomstring = require('randomstring'); - -const { Photo } = require('../../models/photo'); - -jimp.prototype.getBufferAsync = util.promisify(jimp.prototype.getBuffer); - -module.exports = async (req, res, next) => { - const uploadPhoto = util.promisify( - multer({ - dest: '/tmp', - limits: { fileSize: 8388608 }, - fileFilter: (req, file, cb) => { - if (/^image\/(jpe?g|png)$/i.test(file.mimetype)) { - cb(null, true); - } else { - cb(new Error('Should have .jpeg or .png extension')); - } - } - }).single('photo') - ); - try { - await uploadPhoto(req, res); - } catch (err) { - return res.status(400).json({ photo: err.message }); - } - - if (!req.file) { - return res.status(400).json({ photo: 'Is required' }); - } - - let photoFile; - try { - photoFile = await jimp.read(req.file.path); - } catch (err) { - console.log('Photo failed to be read at create-photo'); - return next(err); - } - - if (req.body.isWide === 'true') { - photoFile.cover(640, 480).quality(85); - } else { - photoFile.cover(400, 400).quality(85); - } - - let photoBuffer; - try { - photoBuffer = await photoFile.getBufferAsync(photoFile.getMIME()); - } catch (err) { - return next(err); - } - - const photoExtension = photoFile.getExtension(); - const photoFileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${photoExtension}`; - - const s3 = new aws.S3(); - try { - await s3 - .putObject({ - ACL: 'public-read', - Body: photoBuffer, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: photoFile.getMIME(), - Key: `photos/${photoFileName}` - }) - .promise(); - } catch (err) { - console.log('Photo failed to be uploaded at create-photo'); - return next(err); - } - - fs.unlink(req.file.path); - - const photoData = { - fileName: photoFileName, - url: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/photos/${photoFileName}`, - user: req.user.id - }; - - let photo; - try { - photo = await Photo.create(photoData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log('Photo failed to be created at create-photo'); - return next(err); - } - - const dataResponse = { - id: photo.id, - fileName: photo.fileName, - url: photo.url, - user: photo.user - }; - return res.status(201).json(dataResponse); -}; +const fs = require('fs'); + +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const multer = require('multer'); +const randomstring = require('randomstring'); + +const { Photo } = require('../../models/photo'); + +const upload = multer({ + dest: '/tmp', + limits: { fileSize: 8388608 }, + fileFilter: (req, file, cb) => { + if (/^image\/(jpe?g|png)$/i.test(file.mimetype)) { + cb(null, true); + } else { + cb(new Error('Should have .jpeg or .png extension')); + } + } +}).single('photo'); + +module.exports = async (req, res, next) => { + upload(req, res, async (err) => { + if (err) { + return res.status(400).json({ photo: err.message }); + } + + if (!req.file) { + return res.status(400).json({ photo: 'Is required' }); + } + + let photoFile; + try { + photoFile = await jimp.read(req.file.path); + } catch (err) { + console.log('Photo failed to be read at create-photo'); + return next(err); + } + + if (req.body.isWide === 'true') { + photoFile.cover(640, 480).quality(85); + } else { + photoFile.cover(400, 400).quality(85); + } + + let photoBuffer; + try { + photoBuffer = await photoFile.getBufferAsync(photoFile.getMIME()); + } catch (err) { + return next(err); + } + + const photoExtension = photoFile.getExtension(); + const photoFileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${photoExtension}`; + + const s3 = new aws.S3(); + try { + await s3 + .putObject({ + ACL: 'public-read', + Body: photoBuffer, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: photoFile.getMIME(), + Key: `photos/${photoFileName}` + }) + .promise(); + } catch (err) { + console.log('Photo failed to be uploaded at create-photo'); + return next(err); + } + + fs.unlink(req.file.path, (err) => { + if (err) { + console.log('Failed to delete temporary file', err); + } + }); + + const photoData = { + fileName: photoFileName, + url: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/photos/${photoFileName}`, + user: req.user.id + }; + + let photo; + try { + photo = await Photo.create(photoData); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log('Photo failed to be created at create-photo'); + return next(err); + } + + const dataResponse = { + id: photo.id, + fileName: photo.fileName, + url: photo.url, + user: photo.user + }; + return res.status(201).json(dataResponse); + }); +}; diff --git a/src/routes/photos/delete-photo.js b/src/routes/photos/delete-photo.js index fa78064..a859696 100644 --- a/src/routes/photos/delete-photo.js +++ b/src/routes/photos/delete-photo.js @@ -1,47 +1,47 @@ -const aws = require('aws-sdk'); - -const { Photo } = require('../../models/photo'); - -module.exports = async (req, res, next) => { - const photoFileName = req.params.photoFileName; - - let photo; - try { - photo = await Photo.findOne({ fileName: photoFileName }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Photo not found' }); - } - - console.log(`Photo ${photoFileName} failed to be found at delete-photo`); - return next(err); - } - - if (photo) { - try { - await photo.remove(); - } catch (err) { - console.log( - `Photo ${photoFileName} failed to be deleted at delete-photo` - ); - return next(err); - } - } - - if (!photoFileName.includes('default')) { - const s3 = new aws.S3(); - try { - await s3 - .deleteObject({ - Bucket: process.env.AWS_S3_BUCKET, - Key: `photos/${photoFileName}` - }) - .promise(); - } catch (err) { - console.log('Photo failed to be deleted at delete-photo'); - return next(err); - } - } - - return res.status(204).json({ general: 'Success' }); -}; +const aws = require('aws-sdk'); + +const { Photo } = require('../../models/photo'); + +module.exports = async (req, res, next) => { + const photoFileName = req.params.photoFileName; + + let photo; + try { + photo = await Photo.findOne({ fileName: photoFileName }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Photo not found' }); + } + + console.log(`Photo ${photoFileName} failed to be found at delete-photo`); + return next(err); + } + + if (photo) { + try { + await photo.remove(); + } catch (err) { + console.log( + `Photo ${photoFileName} failed to be deleted at delete-photo` + ); + return next(err); + } + } + + if (!photoFileName.includes('default')) { + const s3 = new aws.S3(); + try { + await s3 + .deleteObject({ + Bucket: process.env.AWS_S3_BUCKET, + Key: `photos/${photoFileName}` + }) + .promise(); + } catch (err) { + console.log('Photo failed to be deleted at delete-photo'); + return next(err); + } + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/photos/index.js b/src/routes/photos/index.js index bd00f27..c1c7280 100644 --- a/src/routes/photos/index.js +++ b/src/routes/photos/index.js @@ -1,17 +1,17 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createPhoto = require('./create-photo'); -const deletePhoto = require('./delete-photo'); - -const router = new express.Router(); - -router.post('', isAuthenticated({ isOptional: false }), createPhoto); -router.delete( - '/:photoFileName', - isAuthenticated({ isOptional: false }), - deletePhoto -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const createPhoto = require('./create-photo'); +const deletePhoto = require('./delete-photo'); + +const router = new express.Router(); + +router.post('', isAuthenticated({ isOptional: false }), createPhoto); +router.delete( + '/:photoFileName', + isAuthenticated({ isOptional: false }), + deletePhoto +); + +module.exports = router; diff --git a/src/routes/reviews/ban-review.js b/src/routes/reviews/ban-review.js index 6e97ee9..227507e 100644 --- a/src/routes/reviews/ban-review.js +++ b/src/routes/reviews/ban-review.js @@ -1,39 +1,39 @@ -const moment = require('moment'); - -const { Review } = require('../../models/review'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at ban-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - review.isBanned = true; - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - console.log(`Review ${review.id} failed to be updated at ban-review`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Review } = require('../../models/review'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at ban-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + review.isBanned = true; + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + console.log(`Review ${review.id} failed to be updated at ban-review`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/reviews/create-review.js b/src/routes/reviews/create-review.js index ff61b71..7b78f17 100644 --- a/src/routes/reviews/create-review.js +++ b/src/routes/reviews/create-review.js @@ -1,557 +1,555 @@ -const axios = require('axios'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Photo } = require('../../models/photo'); -const { Review } = require('../../models/review'); -const { Team } = require('../../models/team'); -const { Venue } = require('../../models/venue'); - -const { validateCreateEditReview } = require('./validations'); -const venueReviewSummary = require('../../helpers/venue-review-summary.js'); - -module.exports = async (req, res, next) => { - console.log('body: ', req.body); - const { errors, isValid } = validateCreateEditReview(req.body); - if (!isValid) return res.status(400).json(errors); - - const data = { - //new expanded fields - hasPermanentRamp: req.body.hasPermanentRamp, - hasPortableRamp: req.body.hasPortableRamp, - hasWideEntrance: req.body.hasWideEntrance, - hasAccessibleTableHeight: req.body.hasAccessibleTableHeight, - hasAccessibleElevator: req.body.hasAccessibleElevator, - hasInteriorRamp: req.body.hasInteriorRamp, - hasSwingOutDoor: req.body.hasSwingOutDoor, - hasLargeStall: req.body.hasLargeStall, - hasSupportAroundToilet: req.body.hasSupportAroundToilet, - hasLoweredSinks: req.body.hasLoweredSinks, - interiorScore: req.body.interiorScore, - _isScoreConverted: true, - - //original fields - allowsGuideDog: req.body.allowsGuideDog, - //bathroomScore: req.body.bathroomScore, - comments: req.body.comments, - //entryScore: req.body.entryScore, - event: req.body.event, - hasParking: req.body.hasParking, - hasSecondEntry: req.body.hasSecondEntry, - hasWellLit: req.body.hasWellLit, - isQuiet: req.body.isQuiet, - isSpacious: req.body.isSpacious, - steps: req.body.steps, - team: req.body.team, - user: req.user.id - }; - - let event; - if (data.event) { - try { - event = await Event.findOne({ _id: data.event, isArchived: false }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-review`); - return next(err); - } - - if (!event) { - return res.status(404).json({ event: 'Event not found' }); - } - - if ( - !event.participants.find(p => p.toString() === data.user) && - !event.managers.find(m => m.toString() === data.user) - ) { - return res - .status(400) - .json({ event: 'You are not a participant of this event' }); - } - - const startDate = moment(event.startDate).utc(); - const endDate = moment(event.endDate).utc(); - const today = moment() - .startOf('day') - .utc(); - if (startDate.isAfter(today)) { - return res.status(400).json({ event: 'Event has not started yet' }); - } else if (endDate.isBefore(today)) { - return res.status(400).json({ event: 'Event has already finished' }); - } - } - - let team; - if (data.team) { - try { - team = await Team.findOne({ _id: data.team, isArchived: false }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-review`); - return next(err); - } - - if (!team) { - return res.status(404).json({ team: 'Team not found' }); - } - - if ( - !team.members.find(m => m.toString() === data.user) && - !team.managers.find(m => m.toString() === data.user) - ) { - return res - .status(400) - .json({ team: 'You are not a member of this team' }); - } - } - - const placeId = req.body.place; - let venue; - try { - venue = await Venue.findOne({ placeId }); - } catch (err) { - console.log( - `Venue with placeId ${placeId} failed to be found at create-review` - ); - return next(err); - } - - if (!venue) { - let response; - try { - response = await axios.get( - `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ - process.env.PLACES_API_KEY - }` - ); - } catch (err) { - console.log( - `Place ${placeId} failed to be found at create-review, after Google search` - ); - return next(err); - } - - const statusResponse = response.data.status; - if (statusResponse !== 'OK') { - return res.status(404).json({ general: 'Place not found' }); - } - - const placeData = response.data.result; - const venueData = { - address: placeData.formatted_address, - location: { - coordinates: [ - placeData.geometry.location.lng, - placeData.geometry.location.lat - ] - }, - name: placeData.name, - placeId, - types: placeData.types - }; - - try { - venue = await Venue.create(venueData); - } catch (err) { - console.log( - `Venue failed to be created at create-review.\nData: ${JSON.stringify( - venueData - )}` - ); - return next(err); - } - } - data.venue = venue.id; - - let review; - try { - review = await Review.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Review failed to be created at create-review.\nData: ${JSON.stringify( - data - )}` - ); - return next(err); - } - - // Sample review Obj - /* - _isScoreConverted: false, - isBanned: false, - voters: [], - _id: 5e853db2587b2740c501f12e, - hasAccessibleElevator: true, - hasInteriorRamp: true, - hasSwingOutDoor: false, - hasLargeStall: false, - user: 5e14e8584701fb22ade354e9, - venue: 5e3da8d56d958200424ffdfe, - complaints: [], - createdAt: 2020-04-02T01:19:46.508Z, - updatedAt: 2020-04-02T01:19:46.508Z, - __v: 0 - */ - - //subtracts out the 10 standard fields to determine - var reviewedFieldsCount = Object.keys(review.toObject()).length - 10; - req.user.reviewFieldsAmount = - req.user.reviewFieldsAmount + reviewedFieldsCount; - req.user.reviewsAmount = req.user.reviewsAmount + 1; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log( - `User ${ - req.user.id - } failed to be updated at create-review, after updated review count` - ); - return next(err); - } - - if (event) { - event.reviewsAmount = event.reviewsAmount + 1; - event.updatedAt = moment.utc().toDate(); - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at create-review, after event` - ); - return next(err); - } - } - - if (req.body.photo) { - let photo; - try { - photo = await Photo.findOne({ url: req.body.photo }); - } catch (err) { - console.log( - `Photo ${req.body.photo} failed to be found at create-review` - ); - return next(err); - } - - if (!photo) { - return res.status(404).json({ photo: 'Not found' }); - } - - venue.photos = [...venue.photos, photo.id]; - - try { - await venue.save(); - } catch (err) { - console.log( - `Venue ${venue.id} failed to be updated at create-review, after photos` - ); - return next(err); - } - } - - if (team) { - team.reviewsAmount = team.reviewsAmount + 1; - team.updatedAt = moment.utc().toDate(); - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at create-review, after team` - ); - return next(err); - } - } - - // - //new expanded fields - // - if (typeof review.hasPermanentRamp !== 'undefined') { - venue.hasPermanentRamp = { - yes: review.hasPermanentRamp - ? venue.hasPermanentRamp.yes + 1 - : venue.hasPermanentRamp.yes, - no: review.hasPermanentRamp - ? venue.hasPermanentRamp.no - : venue.hasPermanentRamp.no + 1 - }; - } - - if (typeof review.hasPortableRamp !== 'undefined') { - venue.hasPortableRamp = { - yes: review.hasPortableRamp - ? venue.hasPortableRamp.yes + 1 - : venue.hasPortableRamp.yes, - no: review.hasPortableRamp - ? venue.hasPortableRamp.no - : venue.hasPortableRamp.no + 1 - }; - } - - if (typeof review.hasWideEntrance !== 'undefined') { - venue.hasWideEntrance = { - yes: review.hasWideEntrance - ? venue.hasWideEntrance.yes + 1 - : venue.hasWideEntrance.yes, - no: review.hasWideEntrance - ? venue.hasWideEntrance.no - : venue.hasWideEntrance.no + 1 - }; - } - - if (typeof review.hasAccessibleTableHeight !== 'undefined') { - venue.hasAccessibleTableHeight = { - yes: review.hasAccessibleTableHeight - ? venue.hasAccessibleTableHeight.yes + 1 - : venue.hasAccessibleTableHeight.yes, - no: review.hasAccessibleTableHeight - ? venue.hasAccessibleTableHeight.no - : venue.hasAccessibleTableHeight.no + 1 - }; - } - - if (typeof review.hasAccessibleElevator !== 'undefined') { - venue.hasAccessibleElevator = { - yes: review.hasAccessibleElevator - ? venue.hasAccessibleElevator.yes + 1 - : venue.hasAccessibleElevator.yes, - no: review.hasAccessibleElevator - ? venue.hasAccessibleElevator.no - : venue.hasAccessibleElevator.no + 1 - }; - } - - if (typeof review.hasInteriorRamp !== 'undefined') { - venue.hasInteriorRamp = { - yes: review.hasInteriorRamp - ? venue.hasInteriorRamp.yes + 1 - : venue.hasInteriorRamp.yes, - no: review.hasInteriorRamp - ? venue.hasInteriorRamp.no - : venue.hasInteriorRamp.no + 1 - }; - } - - if (typeof review.hasSwingOutDoor !== 'undefined') { - venue.hasSwingOutDoor = { - yes: review.hasSwingOutDoor - ? venue.hasSwingOutDoor.yes + 1 - : venue.hasSwingOutDoor.yes, - no: review.hasSwingOutDoor - ? venue.hasSwingOutDoor.no - : venue.hasSwingOutDoor.no + 1 - }; - } - - if (typeof review.hasLargeStall !== 'undefined') { - venue.hasLargeStall = { - yes: review.hasLargeStall - ? venue.hasLargeStall.yes + 1 - : venue.hasLargeStall.yes, - no: review.hasLargeStall - ? venue.hasLargeStall.no - : venue.hasLargeStall.no + 1 - }; - } - - if (typeof review.hasSupportAroundToilet !== 'undefined') { - venue.hasSupportAroundToilet = { - yes: review.hasSupportAroundToilet - ? venue.hasSupportAroundToilet.yes + 1 - : venue.hasSupportAroundToilet.yes, - no: review.hasSupportAroundToilet - ? venue.hasSupportAroundToilet.no - : venue.hasSupportAroundToilet.no + 1 - }; - } - - if (typeof review.hasLoweredSinks !== 'undefined') { - venue.hasLoweredSinks = { - yes: review.hasLoweredSinks - ? venue.hasLoweredSinks.yes + 1 - : venue.hasLoweredSinks.yes, - no: review.hasLoweredSinks - ? venue.hasLoweredSinks.no - : venue.hasLoweredSinks.no + 1 - }; - } - - // - //original fields - // - if (typeof review.allowsGuideDog !== 'undefined') { - venue.allowsGuideDog = { - yes: review.allowsGuideDog - ? venue.allowsGuideDog.yes + 1 - : venue.allowsGuideDog.yes, - no: review.allowsGuideDog - ? venue.allowsGuideDog.no - : venue.allowsGuideDog.no + 1 - }; - } - - /* - if (typeof review.bathroomScore !== 'undefined') { - if (venue.bathroomReviews > 0) { - venue.bathroomScore = - (venue.bathroomScore * venue.bathroomReviews + review.bathroomScore) / - (venue.bathroomReviews + 1); - venue.bathroomReviews += 1; - } else { - venue.bathroomScore = review.bathroomScore; - venue.bathroomReviews = 1; - } - } - - if (venue.entryReviews > 0) { - venue.entryScore = - (venue.entryScore * venue.entryReviews + review.entryScore) / - (venue.entryReviews + 1); - venue.entryReviews += 1; - } else { - venue.entryScore = review.entryScore; - venue.entryReviews = 1; - } - */ - - if (typeof review.hasParking !== 'undefined') { - venue.hasParking = { - yes: review.hasParking ? venue.hasParking.yes + 1 : venue.hasParking.yes, - no: review.hasParking ? venue.hasParking.no : venue.hasParking.no + 1 - }; - } - - if (typeof review.hasSecondEntry !== 'undefined') { - venue.hasSecondEntry = { - yes: review.hasSecondEntry - ? venue.hasSecondEntry.yes + 1 - : venue.hasSecondEntry.yes, - no: review.hasSecondEntry - ? venue.hasSecondEntry.no - : venue.hasSecondEntry.no + 1 - }; - } - - if (typeof review.hasWellLit !== 'undefined') { - venue.hasWellLit = { - yes: review.hasWellLit ? venue.hasWellLit.yes + 1 : venue.hasWellLit.yes, - no: review.hasWellLit ? venue.hasWellLit.no : venue.hasWellLit.no + 1 - }; - } - - if (typeof review.isQuiet !== 'undefined') { - venue.isQuiet = { - yes: review.isQuiet ? venue.isQuiet.yes + 1 : venue.isQuiet.yes, - no: review.isQuiet ? venue.isQuiet.no : venue.isQuiet.no + 1 - }; - } - - if (typeof review.isSpacious !== 'undefined') { - venue.isSpacious = { - yes: review.isSpacious ? venue.isSpacious.yes + 1 : venue.isSpacious.yes, - no: review.isSpacious ? venue.isSpacious.no : venue.isSpacious.no + 1 - }; - } - - venue.reviews = [...venue.reviews, review.id]; - - if (typeof review.steps !== 'undefined') { - venue.steps = { - zero: review.steps === 0 ? venue.steps.zero + 1 : venue.steps.zero, - one: review.steps === 1 ? venue.steps.one + 1 : venue.steps.one, - two: review.steps === 2 ? venue.steps.two + 1 : venue.steps.two, - moreThanTwo: - review.steps === 3 - ? venue.steps.moreThanTwo + 1 - : venue.steps.moreThanTwo - }; - } - - let scoring; - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); - //console.log('entrance score: ', scoring); - venue.entranceScore = scoring.ratingLevel; - venue.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue); - //console.log('interior score: ', scoring); - venue.interiorScore = scoring.ratingLevel; - venue.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); - //console.log('restroom score: ', scoring); - venue.restroomScore = scoring.ratingLevel; - venue.restroomGlyphs = scoring.ratingGlyphs; - - venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - venue.entranceScore, - venue.interiorScore, - venue.restroomScore - ); - - //console.log('venue: ', venue); - - try { - await venue.save(); - } catch (err) { - console.log( - `Venue ${venue.id} failed to be updated at create-review, at final step` - ); - return next(err); - } - - const dataResponse = { - //new expanded fields - hasPermanentRamp: review.hasPermanentRamp, - hasPortableRamp: req.body.hasPortableRamp, - hasWideEntrance: review.hasWideEntrance, - hasAccessibleTableHeight: review.hasAccessibleTableHeight, - hasAccessibleElevator: review.hasAccessibleElevator, - hasInteriorRamp: review.hasInteriorRamp, - hasSwingOutDoor: review.hasSwingOutDoor, - hasLargeStall: review.hasLargeStall, - hasSupportAroundToilet: review.hasSupportAroundToilet, - hasLoweredSinks: review.hasLoweredSinks, - - /* - entranceScore: review.entranceScore, - entranceGlyph: review.entryGlyph, - interiorScore: review.interiorScore, - interiorGlyph: review.interiorGlyph, - restroomScore: review.restroomScore, - restroomGlyph: review.restroomGlyph, - */ - - //original fields - id: review.id, - allowsGuideDog: review.allowsGuideDog, - //bathroomScore: review.bathroomScore, - comments: review.comments, - //entryScore: review.entryScore, - event: review.event, - hasParking: review.hasParking, - hasSecondEntry: review.hasSecondEntry, - hasWellLit: review.hasWellLit, - isQuiet: review.isQuiet, - isSpacious: review.isSpacious, - steps: review.steps, - team: review.team, - user: review.user, - userReviewFieldsAmount: req.user.reviewFieldsAmount, - userReviewsAmount: req.user.reviewsAmount, - venue: review.venue - }; - return res.status(201).json(dataResponse); -}; +const axios = require('axios'); +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Photo } = require('../../models/photo'); +const { Review } = require('../../models/review'); +const { Team } = require('../../models/team'); +const { Venue } = require('../../models/venue'); + +const { validateCreateEditReview } = require('./validations'); +const venueReviewSummary = require('../../helpers/venue-review-summary.js'); + +module.exports = async (req, res, next) => { + console.log('body: ', req.body); + const { errors, isValid } = validateCreateEditReview(req.body); + if (!isValid) return res.status(400).json(errors); + + const data = { + //new expanded fields + hasPermanentRamp: req.body.hasPermanentRamp, + hasPortableRamp: req.body.hasPortableRamp, + hasWideEntrance: req.body.hasWideEntrance, + hasAccessibleTableHeight: req.body.hasAccessibleTableHeight, + hasAccessibleElevator: req.body.hasAccessibleElevator, + hasInteriorRamp: req.body.hasInteriorRamp, + hasSwingOutDoor: req.body.hasSwingOutDoor, + hasLargeStall: req.body.hasLargeStall, + hasSupportAroundToilet: req.body.hasSupportAroundToilet, + hasLoweredSinks: req.body.hasLoweredSinks, + interiorScore: req.body.interiorScore, + _isScoreConverted: true, + + //original fields + allowsGuideDog: req.body.allowsGuideDog, + //bathroomScore: req.body.bathroomScore, + comments: req.body.comments, + //entryScore: req.body.entryScore, + event: req.body.event, + hasParking: req.body.hasParking, + hasSecondEntry: req.body.hasSecondEntry, + hasWellLit: req.body.hasWellLit, + isQuiet: req.body.isQuiet, + isSpacious: req.body.isSpacious, + steps: req.body.steps, + team: req.body.team, + user: req.user.id + }; + + let event; + if (data.event) { + try { + event = await Event.findOne({ _id: data.event, isArchived: false }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-review`); + return next(err); + } + + if (!event) { + return res.status(404).json({ event: 'Event not found' }); + } + + if ( + !event.participants.find((p) => p.toString() === data.user) && + !event.managers.find((m) => m.toString() === data.user) + ) { + return res + .status(400) + .json({ event: 'You are not a participant of this event' }); + } + + const startDate = moment(event.startDate).utc(); + const endDate = moment(event.endDate).utc(); + const today = moment().startOf('day').utc(); + if (startDate.isAfter(today)) { + return res.status(400).json({ event: 'Event has not started yet' }); + } else if (endDate.isBefore(today)) { + return res.status(400).json({ event: 'Event has already finished' }); + } + } + + let team; + if (data.team) { + try { + team = await Team.findOne({ _id: data.team, isArchived: false }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-review`); + return next(err); + } + + if (!team) { + return res.status(404).json({ team: 'Team not found' }); + } + + if ( + !team.members.find((m) => m.toString() === data.user) && + !team.managers.find((m) => m.toString() === data.user) + ) { + return res + .status(400) + .json({ team: 'You are not a member of this team' }); + } + } + + const placeId = req.body.place; + let venue; + try { + venue = await Venue.findOne({ placeId }); + } catch (err) { + console.log( + `Venue with placeId ${placeId} failed to be found at create-review` + ); + return next(err); + } + + if (!venue) { + let response; + try { + response = await axios.get( + `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ + process.env.PLACES_API_KEY + }` + ); + } catch (err) { + console.log( + `Place ${placeId} failed to be found at create-review, after Google search` + ); + return next(err); + } + + const statusResponse = response.data.status; + if (statusResponse !== 'OK') { + return res.status(404).json({ general: 'Place not found' }); + } + + const placeData = response.data.result; + const venueData = { + address: placeData.formatted_address, + location: { + coordinates: [ + placeData.geometry.location.lng, + placeData.geometry.location.lat + ] + }, + name: placeData.name, + placeId, + types: placeData.types + }; + + try { + venue = await Venue.create(venueData); + } catch (err) { + console.log( + `Venue failed to be created at create-review.\nData: ${JSON.stringify( + venueData + )}` + ); + return next(err); + } + } + data.venue = venue.id; + + let review; + try { + review = await Review.create(data); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Review failed to be created at create-review.\nData: ${JSON.stringify( + data + )}` + ); + return next(err); + } + + // Sample review Obj + /* + _isScoreConverted: false, + isBanned: false, + voters: [], + _id: 5e853db2587b2740c501f12e, + hasAccessibleElevator: true, + hasInteriorRamp: true, + hasSwingOutDoor: false, + hasLargeStall: false, + user: 5e14e8584701fb22ade354e9, + venue: 5e3da8d56d958200424ffdfe, + complaints: [], + createdAt: 2020-04-02T01:19:46.508Z, + updatedAt: 2020-04-02T01:19:46.508Z, + __v: 0 + */ + + //subtracts out the 10 standard fields to determine + var reviewedFieldsCount = Object.keys(review.toObject()).length - 10; + req.user.reviewFieldsAmount = + req.user.reviewFieldsAmount + reviewedFieldsCount; + req.user.reviewsAmount = req.user.reviewsAmount + 1; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log( + `User ${ + req.user.id + } failed to be updated at create-review, after updated review count` + ); + return next(err); + } + + if (event) { + event.reviewsAmount = event.reviewsAmount + 1; + event.updatedAt = moment.utc().toDate(); + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at create-review, after event` + ); + return next(err); + } + } + + if (req.body.photo) { + let photo; + try { + photo = await Photo.findOne({ url: req.body.photo }); + } catch (err) { + console.log( + `Photo ${req.body.photo} failed to be found at create-review` + ); + return next(err); + } + + if (!photo) { + return res.status(404).json({ photo: 'Not found' }); + } + + venue.photos = [...venue.photos, photo.id]; + + try { + await venue.save(); + } catch (err) { + console.log( + `Venue ${venue.id} failed to be updated at create-review, after photos` + ); + return next(err); + } + } + + if (team) { + team.reviewsAmount = team.reviewsAmount + 1; + team.updatedAt = moment.utc().toDate(); + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at create-review, after team` + ); + return next(err); + } + } + + // + //new expanded fields + // + if (typeof review.hasPermanentRamp !== 'undefined') { + venue.hasPermanentRamp = { + yes: review.hasPermanentRamp + ? venue.hasPermanentRamp.yes + 1 + : venue.hasPermanentRamp.yes, + no: review.hasPermanentRamp + ? venue.hasPermanentRamp.no + : venue.hasPermanentRamp.no + 1 + }; + } + + if (typeof review.hasPortableRamp !== 'undefined') { + venue.hasPortableRamp = { + yes: review.hasPortableRamp + ? venue.hasPortableRamp.yes + 1 + : venue.hasPortableRamp.yes, + no: review.hasPortableRamp + ? venue.hasPortableRamp.no + : venue.hasPortableRamp.no + 1 + }; + } + + if (typeof review.hasWideEntrance !== 'undefined') { + venue.hasWideEntrance = { + yes: review.hasWideEntrance + ? venue.hasWideEntrance.yes + 1 + : venue.hasWideEntrance.yes, + no: review.hasWideEntrance + ? venue.hasWideEntrance.no + : venue.hasWideEntrance.no + 1 + }; + } + + if (typeof review.hasAccessibleTableHeight !== 'undefined') { + venue.hasAccessibleTableHeight = { + yes: review.hasAccessibleTableHeight + ? venue.hasAccessibleTableHeight.yes + 1 + : venue.hasAccessibleTableHeight.yes, + no: review.hasAccessibleTableHeight + ? venue.hasAccessibleTableHeight.no + : venue.hasAccessibleTableHeight.no + 1 + }; + } + + if (typeof review.hasAccessibleElevator !== 'undefined') { + venue.hasAccessibleElevator = { + yes: review.hasAccessibleElevator + ? venue.hasAccessibleElevator.yes + 1 + : venue.hasAccessibleElevator.yes, + no: review.hasAccessibleElevator + ? venue.hasAccessibleElevator.no + : venue.hasAccessibleElevator.no + 1 + }; + } + + if (typeof review.hasInteriorRamp !== 'undefined') { + venue.hasInteriorRamp = { + yes: review.hasInteriorRamp + ? venue.hasInteriorRamp.yes + 1 + : venue.hasInteriorRamp.yes, + no: review.hasInteriorRamp + ? venue.hasInteriorRamp.no + : venue.hasInteriorRamp.no + 1 + }; + } + + if (typeof review.hasSwingOutDoor !== 'undefined') { + venue.hasSwingOutDoor = { + yes: review.hasSwingOutDoor + ? venue.hasSwingOutDoor.yes + 1 + : venue.hasSwingOutDoor.yes, + no: review.hasSwingOutDoor + ? venue.hasSwingOutDoor.no + : venue.hasSwingOutDoor.no + 1 + }; + } + + if (typeof review.hasLargeStall !== 'undefined') { + venue.hasLargeStall = { + yes: review.hasLargeStall + ? venue.hasLargeStall.yes + 1 + : venue.hasLargeStall.yes, + no: review.hasLargeStall + ? venue.hasLargeStall.no + : venue.hasLargeStall.no + 1 + }; + } + + if (typeof review.hasSupportAroundToilet !== 'undefined') { + venue.hasSupportAroundToilet = { + yes: review.hasSupportAroundToilet + ? venue.hasSupportAroundToilet.yes + 1 + : venue.hasSupportAroundToilet.yes, + no: review.hasSupportAroundToilet + ? venue.hasSupportAroundToilet.no + : venue.hasSupportAroundToilet.no + 1 + }; + } + + if (typeof review.hasLoweredSinks !== 'undefined') { + venue.hasLoweredSinks = { + yes: review.hasLoweredSinks + ? venue.hasLoweredSinks.yes + 1 + : venue.hasLoweredSinks.yes, + no: review.hasLoweredSinks + ? venue.hasLoweredSinks.no + : venue.hasLoweredSinks.no + 1 + }; + } + + // + //original fields + // + if (typeof review.allowsGuideDog !== 'undefined') { + venue.allowsGuideDog = { + yes: review.allowsGuideDog + ? venue.allowsGuideDog.yes + 1 + : venue.allowsGuideDog.yes, + no: review.allowsGuideDog + ? venue.allowsGuideDog.no + : venue.allowsGuideDog.no + 1 + }; + } + + /* + if (typeof review.bathroomScore !== 'undefined') { + if (venue.bathroomReviews > 0) { + venue.bathroomScore = + (venue.bathroomScore * venue.bathroomReviews + review.bathroomScore) / + (venue.bathroomReviews + 1); + venue.bathroomReviews += 1; + } else { + venue.bathroomScore = review.bathroomScore; + venue.bathroomReviews = 1; + } + } + + if (venue.entryReviews > 0) { + venue.entryScore = + (venue.entryScore * venue.entryReviews + review.entryScore) / + (venue.entryReviews + 1); + venue.entryReviews += 1; + } else { + venue.entryScore = review.entryScore; + venue.entryReviews = 1; + } + */ + + if (typeof review.hasParking !== 'undefined') { + venue.hasParking = { + yes: review.hasParking ? venue.hasParking.yes + 1 : venue.hasParking.yes, + no: review.hasParking ? venue.hasParking.no : venue.hasParking.no + 1 + }; + } + + if (typeof review.hasSecondEntry !== 'undefined') { + venue.hasSecondEntry = { + yes: review.hasSecondEntry + ? venue.hasSecondEntry.yes + 1 + : venue.hasSecondEntry.yes, + no: review.hasSecondEntry + ? venue.hasSecondEntry.no + : venue.hasSecondEntry.no + 1 + }; + } + + if (typeof review.hasWellLit !== 'undefined') { + venue.hasWellLit = { + yes: review.hasWellLit ? venue.hasWellLit.yes + 1 : venue.hasWellLit.yes, + no: review.hasWellLit ? venue.hasWellLit.no : venue.hasWellLit.no + 1 + }; + } + + if (typeof review.isQuiet !== 'undefined') { + venue.isQuiet = { + yes: review.isQuiet ? venue.isQuiet.yes + 1 : venue.isQuiet.yes, + no: review.isQuiet ? venue.isQuiet.no : venue.isQuiet.no + 1 + }; + } + + if (typeof review.isSpacious !== 'undefined') { + venue.isSpacious = { + yes: review.isSpacious ? venue.isSpacious.yes + 1 : venue.isSpacious.yes, + no: review.isSpacious ? venue.isSpacious.no : venue.isSpacious.no + 1 + }; + } + + venue.reviews = [...venue.reviews, review.id]; + + if (typeof review.steps !== 'undefined') { + venue.steps = { + zero: review.steps === 0 ? venue.steps.zero + 1 : venue.steps.zero, + one: review.steps === 1 ? venue.steps.one + 1 : venue.steps.one, + two: review.steps === 2 ? venue.steps.two + 1 : venue.steps.two, + moreThanTwo: + review.steps === 3 + ? venue.steps.moreThanTwo + 1 + : venue.steps.moreThanTwo + }; + } + + let scoring; + //calculate entranceScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); + //console.log('entrance score: ', scoring); + venue.entranceScore = scoring.ratingLevel; + venue.entranceGlyphs = scoring.ratingGlyphs; + + //calculate interiorScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('interior', venue); + //console.log('interior score: ', scoring); + venue.interiorScore = scoring.ratingLevel; + venue.interiorGlyphs = scoring.ratingGlyphs; + + //calculate restroomScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); + //console.log('restroom score: ', scoring); + venue.restroomScore = scoring.ratingLevel; + venue.restroomGlyphs = scoring.ratingGlyphs; + + venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( + venue.entranceScore, + venue.interiorScore, + venue.restroomScore + ); + + //console.log('venue: ', venue); + + try { + await venue.save(); + } catch (err) { + console.log( + `Venue ${venue.id} failed to be updated at create-review, at final step` + ); + return next(err); + } + + const dataResponse = { + //new expanded fields + hasPermanentRamp: review.hasPermanentRamp, + hasPortableRamp: req.body.hasPortableRamp, + hasWideEntrance: review.hasWideEntrance, + hasAccessibleTableHeight: review.hasAccessibleTableHeight, + hasAccessibleElevator: review.hasAccessibleElevator, + hasInteriorRamp: review.hasInteriorRamp, + hasSwingOutDoor: review.hasSwingOutDoor, + hasLargeStall: review.hasLargeStall, + hasSupportAroundToilet: review.hasSupportAroundToilet, + hasLoweredSinks: review.hasLoweredSinks, + + /* + entranceScore: review.entranceScore, + entranceGlyph: review.entryGlyph, + interiorScore: review.interiorScore, + interiorGlyph: review.interiorGlyph, + restroomScore: review.restroomScore, + restroomGlyph: review.restroomGlyph, + */ + + //original fields + id: review.id, + allowsGuideDog: review.allowsGuideDog, + //bathroomScore: review.bathroomScore, + comments: review.comments, + //entryScore: review.entryScore, + event: review.event, + hasParking: review.hasParking, + hasSecondEntry: review.hasSecondEntry, + hasWellLit: review.hasWellLit, + isQuiet: review.isQuiet, + isSpacious: review.isSpacious, + steps: review.steps, + team: review.team, + user: review.user, + userReviewFieldsAmount: req.user.reviewFieldsAmount, + userReviewsAmount: req.user.reviewsAmount, + venue: review.venue + }; + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/reviews/edit-review.js b/src/routes/reviews/edit-review.js index dd59ebf..251c2d5 100644 --- a/src/routes/reviews/edit-review.js +++ b/src/routes/reviews/edit-review.js @@ -1,217 +1,217 @@ -const moment = require('moment'); -const { pick } = require('lodash'); - -const { Event } = require('../../models/event'); -const { Review } = require('../../models/review'); -const { Team } = require('../../models/team'); -const { Venue } = require('../../models/venue'); - -const { validateCreateEditReview } = require('./validations'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }).select( - '-__v -createdAt -updatedAt' - ); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at edit-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - if (review.user.toString() !== req.user.id) { - return res - .status(423) - .json({ general: 'You cannot edit someone else review' }); - } - - let venue; - try { - venue = await Venue.findOne({ - _id: review.venue.toString(), - isArchived: false - }); - } catch (err) { - console.log( - `Venue ${review.venue.toString()} failed to be found at edit-review` - ); - return next(err); - } - - if (!venue) { - return res.status(404).json({ general: 'Review venue not found' }); - } - - const data = pick(req.body, [ - //new expanded fields - 'hasPermanentRamp', - 'hasPortableRamp', - 'hasWideEntrance', - 'hasAccessibleTableHeight', - 'hasAccessibleElevator', - 'hasInteriorRamp', - 'hasSwingOutDoor', - 'hasLargeStall', - 'hasSupportAroundToilet', - 'hasLoweredSinks', - - //original fields - //'bathroomScore', - 'comments', - //'entryScore', - 'event', - 'guideDog', - 'parking', - 'quiet', - 'ramp', - 'secondEntry', - 'spacious', - 'steps', - 'team', - 'wellLit' - ]); - const { errors, isValid } = validateCreateEditReview(data); - - if (!isValid) { - return res.status(400).json(errors); - } - - //review.bathroomScore = data.bathroomScore || review.bathroomScore; - review.comments = data.comments || review.comments; - //review.entryScore = data.entryScore || review.entryScore; - - if (data.event) { - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at edit-review`); - return next(err); - } - - if (!event) { - return res.status(404).json({ event: 'Event not found' }); - } - - if (!event.participants.find(p => p.toString() === req.user.id)) { - return res - .status(400) - .json({ event: 'You are not a participant of this event' }); - } - - const startDate = moment(event.startDate).utc(); - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - if (startDate.isAfter(today)) { - return res.status(400).json({ event: 'Event has not started yet' }); - } else if (endDate.isBefore(today)) { - return res.status(400).json({ event: 'Event has already finished' }); - } - - review.event = data.event; - } - - review.guideDog = data.guideDog || review.guideDog; - review.parking = data.parking || review.parking; - review.quiet = data.quiet || review.quiet; - review.ramp = data.ramp || review.ramp; - review.secondEntry = data.secondEntry || review.secondEntry; - review.spacious = data.spacious || review.spacious; - - //new expanded fields - review.hasPermanentRamp = data.hasPermanentRamp || review.hasPermanentRamp; - review.hasPortableRamp = data.hasPortableRamp || review.hasPortableRamp; - review.hasWideEntrance = data.hasWideEntrance || review.hasWideEntrance; - review.hasAccessibleTableHeight = - data.hasAccessibleTableHeight || review.hasAccessibleTableHeight; - review.hasAccessibleElevator = - data.hasAccessibleElevator || review.hasAccessibleElevator; - review.hasInteriorRamp = data.hasInteriorRamp || review.hasInteriorRamp; - review.hasSwingOutDoor = data.hasSwingOutDoor || review.hasSwingOutDoor; - review.hasLargeStall = data.hasLargeStall || review.hasLargeStall; - review.hasSupportAroundToilet = - data.hasSupportAroundToilet || review.hasSupportAroundToilet; - review.hasLoweredSinks = data.hasLoweredSinks || review.hasLoweredSinks; - - if (data.steps) { - venue.stepsReviews[review.steps] -= 1; - venue.stepsReviews[data.steps] += 1; - review.steps = data.steps; - } - - if (data.team) { - let team; - try { - team = await Team.findOne({ _id: data.team, isArchived: false }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at edit-review`); - return next(err); - } - - if (!team) { - return res.status(404).json({ team: 'Team not found' }); - } - - if (!team.members.find(m => m.toString() === req.user.id)) { - return res - .status(400) - .json({ team: 'You are not a member of this team' }); - } - - review.team = data.team; - } - - review.wellLit = data.wellLit || review.wellLit; - - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Review ${review.id} failed to be updated at edit-review`); - return next(err); - } - - try { - await venue.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Venue ${venue.id} failed to be updated at edit-review`); - return next(err); - } - - return res.status(200).json(review); -}; +const moment = require('moment'); +const { pick } = require('lodash'); + +const { Event } = require('../../models/event'); +const { Review } = require('../../models/review'); +const { Team } = require('../../models/team'); +const { Venue } = require('../../models/venue'); + +const { validateCreateEditReview } = require('./validations'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }).select( + '-__v -createdAt -updatedAt' + ); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at edit-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + if (review.user.toString() !== req.user.id) { + return res + .status(423) + .json({ general: 'You cannot edit someone else review' }); + } + + let venue; + try { + venue = await Venue.findOne({ + _id: review.venue.toString(), + isArchived: false + }); + } catch (err) { + console.log( + `Venue ${review.venue.toString()} failed to be found at edit-review` + ); + return next(err); + } + + if (!venue) { + return res.status(404).json({ general: 'Review venue not found' }); + } + + const data = pick(req.body, [ + //new expanded fields + 'hasPermanentRamp', + 'hasPortableRamp', + 'hasWideEntrance', + 'hasAccessibleTableHeight', + 'hasAccessibleElevator', + 'hasInteriorRamp', + 'hasSwingOutDoor', + 'hasLargeStall', + 'hasSupportAroundToilet', + 'hasLoweredSinks', + + //original fields + //'bathroomScore', + 'comments', + //'entryScore', + 'event', + 'guideDog', + 'parking', + 'quiet', + 'ramp', + 'secondEntry', + 'spacious', + 'steps', + 'team', + 'wellLit' + ]); + const { errors, isValid } = validateCreateEditReview(data); + + if (!isValid) { + return res.status(400).json(errors); + } + + //review.bathroomScore = data.bathroomScore || review.bathroomScore; + review.comments = data.comments || review.comments; + //review.entryScore = data.entryScore || review.entryScore; + + if (data.event) { + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at edit-review`); + return next(err); + } + + if (!event) { + return res.status(404).json({ event: 'Event not found' }); + } + + if (!event.participants.find((p) => p.toString() === req.user.id)) { + return res + .status(400) + .json({ event: 'You are not a participant of this event' }); + } + + const startDate = moment(event.startDate).utc(); + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + if (startDate.isAfter(today)) { + return res.status(400).json({ event: 'Event has not started yet' }); + } else if (endDate.isBefore(today)) { + return res.status(400).json({ event: 'Event has already finished' }); + } + + review.event = data.event; + } + + review.guideDog = data.guideDog || review.guideDog; + review.parking = data.parking || review.parking; + review.quiet = data.quiet || review.quiet; + review.ramp = data.ramp || review.ramp; + review.secondEntry = data.secondEntry || review.secondEntry; + review.spacious = data.spacious || review.spacious; + + //new expanded fields + review.hasPermanentRamp = data.hasPermanentRamp || review.hasPermanentRamp; + review.hasPortableRamp = data.hasPortableRamp || review.hasPortableRamp; + review.hasWideEntrance = data.hasWideEntrance || review.hasWideEntrance; + review.hasAccessibleTableHeight = + data.hasAccessibleTableHeight || review.hasAccessibleTableHeight; + review.hasAccessibleElevator = + data.hasAccessibleElevator || review.hasAccessibleElevator; + review.hasInteriorRamp = data.hasInteriorRamp || review.hasInteriorRamp; + review.hasSwingOutDoor = data.hasSwingOutDoor || review.hasSwingOutDoor; + review.hasLargeStall = data.hasLargeStall || review.hasLargeStall; + review.hasSupportAroundToilet = + data.hasSupportAroundToilet || review.hasSupportAroundToilet; + review.hasLoweredSinks = data.hasLoweredSinks || review.hasLoweredSinks; + + if (data.steps) { + venue.stepsReviews[review.steps] -= 1; + venue.stepsReviews[data.steps] += 1; + review.steps = data.steps; + } + + if (data.team) { + let team; + try { + team = await Team.findOne({ _id: data.team, isArchived: false }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at edit-review`); + return next(err); + } + + if (!team) { + return res.status(404).json({ team: 'Team not found' }); + } + + if (!team.members.find((m) => m.toString() === req.user.id)) { + return res + .status(400) + .json({ team: 'You are not a member of this team' }); + } + + review.team = data.team; + } + + review.wellLit = data.wellLit || review.wellLit; + + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Review ${review.id} failed to be updated at edit-review`); + return next(err); + } + + try { + await venue.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Venue ${venue.id} failed to be updated at edit-review`); + return next(err); + } + + return res.status(200).json(review); +}; diff --git a/src/routes/reviews/flag-review.js b/src/routes/reviews/flag-review.js index a92319d..9de8ce9 100644 --- a/src/routes/reviews/flag-review.js +++ b/src/routes/reviews/flag-review.js @@ -1,50 +1,50 @@ -const moment = require('moment'); -const { pick } = require('lodash'); - -const { Review } = require('../../models/review'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at flag-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - const data = pick(req.body, ['comments', 'type']); - - review.complaints = [ - ...review.complaints, - { - comments: data.comments, - type: data.type, - user: req.user.id - } - ]; - - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - console.log(`Review ${review.id} failed to be updated at flag-review`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); +const { pick } = require('lodash'); + +const { Review } = require('../../models/review'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at flag-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + const data = pick(req.body, ['comments', 'type']); + + review.complaints = [ + ...review.complaints, + { + comments: data.comments, + type: data.type, + user: req.user.id + } + ]; + + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + console.log(`Review ${review.id} failed to be updated at flag-review`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/reviews/index.js b/src/routes/reviews/index.js index 8031f89..df1af41 100644 --- a/src/routes/reviews/index.js +++ b/src/routes/reviews/index.js @@ -1,29 +1,29 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const banReview = require('./ban-review'); -const createReview = require('./create-review'); -const editReview = require('./edit-review'); -const flagReview = require('./flag-review'); -const listReviews = require('./list-reviews'); -const voteReview = require('./vote-review'); - -const router = new express.Router(); - -router.get('', isAuthenticated({ isOptional: false }), listReviews); -router.post('', isAuthenticated({ isOptional: false }), createReview); -router.put('/:reviewId', isAuthenticated({ isOptional: false }), editReview); -router.put( - '/:reviewId/vote', - isAuthenticated({ isOptional: false }), - voteReview -); -router.post( - '/:reviewId/flag', - isAuthenticated({ isOptional: false }), - flagReview -); -router.put('/:reviewId/ban', isAuthenticated({ isOptional: false }), banReview); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const banReview = require('./ban-review'); +const createReview = require('./create-review'); +const editReview = require('./edit-review'); +const flagReview = require('./flag-review'); +const listReviews = require('./list-reviews'); +const voteReview = require('./vote-review'); + +const router = new express.Router(); + +router.get('', isAuthenticated({ isOptional: false }), listReviews); +router.post('', isAuthenticated({ isOptional: false }), createReview); +router.put('/:reviewId', isAuthenticated({ isOptional: false }), editReview); +router.put( + '/:reviewId/vote', + isAuthenticated({ isOptional: false }), + voteReview +); +router.post( + '/:reviewId/flag', + isAuthenticated({ isOptional: false }), + flagReview +); +router.put('/:reviewId/ban', isAuthenticated({ isOptional: false }), banReview); + +module.exports = router; diff --git a/src/routes/reviews/list-reviews.js b/src/routes/reviews/list-reviews.js index 9050b45..280601c 100644 --- a/src/routes/reviews/list-reviews.js +++ b/src/routes/reviews/list-reviews.js @@ -1,184 +1,184 @@ -const { toBoolean, toInt } = require('validator'); - -const { Review } = require('../../models/review'); - -const { validateListReviews } = require('./validations'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const queryParams = req.query; - const { errors, isValid } = validateListReviews(queryParams); - - if (!isValid) { - return res.status(400).json(errors); - } - - const reviewsQuery = {}; - - if (queryParams.restroomScore) { - //const limits = queryParams.bathroomScore.split(','); - reviewsQuery.bathroomScore = { $gte: toInt(queryParams.bathroomScore) }; - } - - if (queryParams.entranceScore) { - //const limits = queryParams.entryScore.split(','); - reviewsQuery.entranceScore = { $gte: toInt(queryParams.entranceScore) }; - } - - if (queryParams.event) { - reviewsQuery.event = queryParams.event; - } - - if (queryParams.guideDog) { - reviewsQuery.guideDog = toBoolean(queryParams.guideDog); - } - - if (queryParams.parking) { - reviewsQuery.parking = toBoolean(queryParams.parking); - } - - if (queryParams.quiet) { - reviewsQuery.quiet = toBoolean(queryParams.quiet); - } - - if (queryParams.ramp) { - reviewsQuery.ramp = toBoolean(queryParams.ramp); - } - - if (queryParams.secondEntry) { - reviewsQuery.secondEntry = toBoolean(queryParams.secondEntry); - } - - if (queryParams.spacious) { - reviewsQuery.spacious = toBoolean(queryParams.spacious); - } - - if (queryParams.steps) { - reviewsQuery.steps = toInt(queryParams.steps); - } - - if (queryParams.team) { - reviewsQuery.team = queryParams.team; - } - - if (queryParams.user) { - reviewsQuery.user = queryParams.user; - } - - if (queryParams.venue) { - reviewsQuery.venue = queryParams.venue; - } - - if (queryParams.wellLit) { - reviewsQuery.wellLit = toBoolean(queryParams.wellLit); - } - - // - // new expanded fields - // - if (queryParams.hasPermanentRamp) { - reviewsQuery.hasPermanentRamp = toBoolean(queryParams.hasPermanentRamp); - } - - if (queryParams.hasPortableRamp) { - reviewsQuery.hasPortableRamp = toBoolean(queryParams.hasPortableRamp); - } - - if (queryParams.hasWideEntrance) { - reviewsQuery.hasWideEntrance = toBoolean(queryParams.hasWideEntrance); - } - - if (queryParams.hasAccessibleTableHeight) { - reviewsQuery.hasAccessibleTableHeight = toBoolean( - queryParams.hasAccessibleTableHeight - ); - } - - if (queryParams.hasAccessibleElevator) { - reviewsQuery.hasAccessibleElevator = toBoolean( - queryParams.hasAccessibleElevator - ); - } - - if (queryParams.hasInteriorRamp) { - reviewsQuery.hasInteriorRamp = toBoolean(queryParams.hasInteriorRamp); - } - - if (queryParams.hasSwingOutDoor) { - reviewsQuery.hasSwingOutDoor = toBoolean(queryParams.hasSwingOutDoor); - } - - if (queryParams.hasLargeStall) { - reviewsQuery.hasLargeStall = toBoolean(queryParams.hasLargeStall); - } - - if (queryParams.hasSupportAroundToilet) { - reviewsQuery.hasSupportAroundToilet = toBoolean( - queryParams.hasSupportAroundToilet - ); - } - - if (queryParams.hasLoweredSinks) { - reviewsQuery.hasLoweredSinks = toBoolean(queryParams.hasLoweredSinks); - } - - if (queryParams.interiorScore) { - reviewsQuery.interiorScore = { $gte: toInt(queryParams.interiorScore) }; - } - - let page = queryParams.page || 1; - const pageLimit = 18; - - if (page > 0) { - page -= 1; - } else { - return res - .status(400) - .json({ page: 'Should be equal to or greater than 1' }); - } - - let reviews; - let total; - try { - [reviews, total] = await Promise.all([ - Review.find(reviewsQuery) - .select('-__v -updatedAt -createdAt') - .sort('createdAt') - .skip(page * pageLimit) - .limit(pageLimit), - Review.find(reviewsQuery).count() - ]); - } catch (err) { - console.log('Reviews failed to be found or count at list-reviews'); - return next(err); - } - - let first = `${process.env.API_URL}/reviews?page=1`; - const lastPage = Math.ceil(total / pageLimit); - let last = `${process.env.API_URL}/reviews?page=${lastPage}`; - - if (lastPage > 0) { - page += 1; - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - first = null; - last = null; - page = null; - } - - return res.status(200).json({ - first, - last, - page, - pageLimit, - results: reviews, - total - }); -}; +const { toBoolean, toInt } = require('validator'); + +const { Review } = require('../../models/review'); + +const { validateListReviews } = require('./validations'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const queryParams = req.query; + const { errors, isValid } = validateListReviews(queryParams); + + if (!isValid) { + return res.status(400).json(errors); + } + + const reviewsQuery = {}; + + if (queryParams.restroomScore) { + //const limits = queryParams.bathroomScore.split(','); + reviewsQuery.bathroomScore = { $gte: toInt(queryParams.bathroomScore) }; + } + + if (queryParams.entranceScore) { + //const limits = queryParams.entryScore.split(','); + reviewsQuery.entranceScore = { $gte: toInt(queryParams.entranceScore) }; + } + + if (queryParams.event) { + reviewsQuery.event = queryParams.event; + } + + if (queryParams.guideDog) { + reviewsQuery.guideDog = toBoolean(queryParams.guideDog); + } + + if (queryParams.parking) { + reviewsQuery.parking = toBoolean(queryParams.parking); + } + + if (queryParams.quiet) { + reviewsQuery.quiet = toBoolean(queryParams.quiet); + } + + if (queryParams.ramp) { + reviewsQuery.ramp = toBoolean(queryParams.ramp); + } + + if (queryParams.secondEntry) { + reviewsQuery.secondEntry = toBoolean(queryParams.secondEntry); + } + + if (queryParams.spacious) { + reviewsQuery.spacious = toBoolean(queryParams.spacious); + } + + if (queryParams.steps) { + reviewsQuery.steps = toInt(queryParams.steps); + } + + if (queryParams.team) { + reviewsQuery.team = queryParams.team; + } + + if (queryParams.user) { + reviewsQuery.user = queryParams.user; + } + + if (queryParams.venue) { + reviewsQuery.venue = queryParams.venue; + } + + if (queryParams.wellLit) { + reviewsQuery.wellLit = toBoolean(queryParams.wellLit); + } + + // + // new expanded fields + // + if (queryParams.hasPermanentRamp) { + reviewsQuery.hasPermanentRamp = toBoolean(queryParams.hasPermanentRamp); + } + + if (queryParams.hasPortableRamp) { + reviewsQuery.hasPortableRamp = toBoolean(queryParams.hasPortableRamp); + } + + if (queryParams.hasWideEntrance) { + reviewsQuery.hasWideEntrance = toBoolean(queryParams.hasWideEntrance); + } + + if (queryParams.hasAccessibleTableHeight) { + reviewsQuery.hasAccessibleTableHeight = toBoolean( + queryParams.hasAccessibleTableHeight + ); + } + + if (queryParams.hasAccessibleElevator) { + reviewsQuery.hasAccessibleElevator = toBoolean( + queryParams.hasAccessibleElevator + ); + } + + if (queryParams.hasInteriorRamp) { + reviewsQuery.hasInteriorRamp = toBoolean(queryParams.hasInteriorRamp); + } + + if (queryParams.hasSwingOutDoor) { + reviewsQuery.hasSwingOutDoor = toBoolean(queryParams.hasSwingOutDoor); + } + + if (queryParams.hasLargeStall) { + reviewsQuery.hasLargeStall = toBoolean(queryParams.hasLargeStall); + } + + if (queryParams.hasSupportAroundToilet) { + reviewsQuery.hasSupportAroundToilet = toBoolean( + queryParams.hasSupportAroundToilet + ); + } + + if (queryParams.hasLoweredSinks) { + reviewsQuery.hasLoweredSinks = toBoolean(queryParams.hasLoweredSinks); + } + + if (queryParams.interiorScore) { + reviewsQuery.interiorScore = { $gte: toInt(queryParams.interiorScore) }; + } + + let page = queryParams.page || 1; + const pageLimit = 18; + + if (page > 0) { + page -= 1; + } else { + return res + .status(400) + .json({ page: 'Should be equal to or greater than 1' }); + } + + let reviews; + let total; + try { + [reviews, total] = await Promise.all([ + Review.find(reviewsQuery) + .select('-__v -updatedAt -createdAt') + .sort('createdAt') + .skip(page * pageLimit) + .limit(pageLimit), + Review.find(reviewsQuery).count() + ]); + } catch (err) { + console.log('Reviews failed to be found or count at list-reviews'); + return next(err); + } + + let first = `${process.env.API_URL}/reviews?page=1`; + const lastPage = Math.ceil(total / pageLimit); + let last = `${process.env.API_URL}/reviews?page=${lastPage}`; + + if (lastPage > 0) { + page += 1; + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + first = null; + last = null; + page = null; + } + + return res.status(200).json({ + first, + last, + page, + pageLimit, + results: reviews, + total + }); +}; diff --git a/src/routes/reviews/validations.js b/src/routes/reviews/validations.js index 70ea8cb..5a811de 100644 --- a/src/routes/reviews/validations.js +++ b/src/routes/reviews/validations.js @@ -1,376 +1,376 @@ -const { isEmpty } = require('lodash'); -const { isInt, isMongoId } = require('validator'); - -module.exports = { - validateCreateEditReview(data) { - const errors = {}; - - // - // new expanded fields - // - if ( - typeof data.hasPermanentRamp !== 'undefined' && - typeof data.hasPermanentRamp !== 'boolean' - ) { - errors.hasPermanentRamp = 'Should be a boolean'; - } - - if ( - typeof data.hasPortableRamp !== 'undefined' && - typeof data.hasPortableRamp !== 'boolean' - ) { - errors.hasPortableRamp = 'Should be a boolean'; - } - - if ( - typeof data.hasWideEntrance !== 'undefined' && - typeof data.hasWideEntrance !== 'boolean' - ) { - errors.hasWideEntrance = 'Should be a boolean'; - } - - if ( - typeof data.hasAccessibleTableHeight !== 'undefined' && - typeof data.hasAccessibleTableHeight !== 'boolean' - ) { - errors.hasAccessibleTableHeight = 'Should be a boolean'; - } - - if ( - typeof data.hasAccessibleElevator !== 'undefined' && - typeof data.hasAccessibleElevator !== 'boolean' - ) { - errors.hasAccessibleElevator = 'Should be a boolean'; - } - - if ( - typeof data.hasInteriorRamp !== 'undefined' && - typeof data.hasInteriorRamp !== 'boolean' - ) { - errors.hasInteriorRamp = 'Should be a boolean'; - } - - if ( - typeof data.hasSwingOutDoor !== 'undefined' && - typeof data.hasSwingOutDoor !== 'boolean' - ) { - errors.hasSwingOutDoor = 'Should be a boolean'; - } - - if ( - typeof data.hasLargeStall !== 'undefined' && - typeof data.hasLargeStall !== 'boolean' - ) { - errors.hasLargeStall = 'Should be a boolean'; - } - - if ( - typeof data.hasSupportAroundToilet !== 'undefined' && - typeof data.hasSupportAroundToilet !== 'boolean' - ) { - errors.hasSupportAroundToilet = 'Should be a boolean'; - } - - if ( - typeof data.hasLoweredSinks !== 'undefined' && - typeof data.hasLoweredSinks !== 'boolean' - ) { - errors.hasLoweredSinks = 'Should be a boolean'; - } - - /* - *interiorScore - if (typeof data.interiorScore !== 'undefined') { - if (typeof data.interiorScore !== 'number') { - errors.interiorScore = 'Should be a number'; - } else if (data.interiorScore < 1 || data.interiorScore > 7) { - //Remove required interiorScore - //errors.interiorScore = 'Should be between 1 and 7'; - } - } - */ - - // - //original fields - // - if ( - typeof data.allowsGuideDog !== 'undefined' && - typeof data.allowsGuideDog !== 'boolean' - ) { - errors.allowsGuideDog = 'Should be a boolean'; - } - - /* - * bathroomScore - if (typeof data.bathroomScore !== 'undefined') { - if (typeof data.bathroomScore !== 'number') { - errors.bathroomScore = 'Should be a number'; - } else if (data.bathroomScore < 1 || data.bathroomScore > 4) { - //Remove required entryScore - //errors.bathroomScore = 'Should be between 1 and 4'; - } - } - */ - - if (data.comments && typeof data.comments !== 'string') { - errors.comments = 'Should be a string'; - } - - /* - * entryScore - if (typeof data.entryScore === 'undefined') { - //Remove required entryScore - //errors.entryScore = 'Is required'; - } else if (typeof data.entryScore !== 'number') { - errors.entryScore = 'Should be a number'; - } else if (data.entryScore < 1 || data.entryScore > 9) { - //Remove required entryScore - //errors.entryScore = 'Should be between 1 and 9'; - } - */ - - if (data.event) { - if (typeof data.event !== 'string') { - errors.event = 'Should be a string'; - } else if (!isMongoId(data.event)) { - errors.event = 'Should be a valid id'; - } - } - - if ( - typeof data.hasParking !== 'undefined' && - typeof data.hasParking !== 'boolean' - ) { - errors.hasParking = 'Should be a boolean'; - } - - if ( - typeof data.hasSecondEntry !== 'undefined' && - typeof data.hasSecondEntry !== 'boolean' - ) { - errors.hasSecondEntry = 'Should be a boolean'; - } - - if ( - typeof data.hasWellLit !== 'undefined' && - typeof data.hasWellLit !== 'boolean' - ) { - errors.hasWellLit = 'Should be a boolean'; - } - - if ( - typeof data.isQuiet !== 'undefined' && - typeof data.isQuiet !== 'boolean' - ) { - errors.isQuiet = 'Should be a boolean'; - } - - if ( - typeof data.isSpacious !== 'undefined' && - typeof data.isSpacious !== 'boolean' - ) { - errors.isSpacious = 'Should be a boolean'; - } - - if (typeof data.photo !== 'undefined' && typeof data.photo !== 'string') { - errors.photo = 'Should be a string'; - } - - if (!data.place) { - errors.place = 'Is required'; - } else if (typeof data.place !== 'string') { - errors.place = 'Should be a string'; - } - - if (typeof data.steps !== 'undefined') { - if (typeof data.steps !== 'number') { - errors.steps = 'Should be a number'; - } else if (data.steps < 0 || data.steps > 3) { - errors.steps = 'Should be between 0 and 3'; - } - } - - if (data.team) { - if (typeof data.team !== 'string') { - errors.team = 'Should be a string'; - } else if (!isMongoId(data.team)) { - errors.team = 'Should be a valid id'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListReviews(queryParams) { - const errors = {}; - - //Remove bathroomScore validation - if (queryParams.bathroomScore) { - /* - const limits = queryParams.bathroomScore.split(','); - - if (limits.length !== 2) { - errors.bathroomScore = 'Should be two integers split by a comma'; - } else if ( - !isInt(limits[0], { min: 1, max: 4 }) || - !isInt(limits[1], { min: 1, max: 4 }) - ) { - errors.bathroomScore = 'Both should be integers between 1 and 4'; - } - */ - } - - //Remove entryScore validation - if (queryParams.entryScore) { - /* - const limits = queryParams.entryScore.split(','); - - if (limits.length !== 2) { - errors.entryScore = 'Should be two integers split by a comma'; - } else if ( - !isInt(limits[0], { min: 1, max: 9 }) || - !isInt(limits[1], { min: 1, max: 9 }) - ) { - errors.entryScore = 'Both should be integers between 1 and 9'; - } - */ - } - - if (queryParams.event && !isMongoId(queryParams.event)) { - errors.event = 'Should be a valid Id'; - } - - if ( - queryParams.guideDog && - !isInt(queryParams.guideDog, { min: 0, max: 1 }) - ) { - errors.guideDog = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.parking && - !isInt(queryParams.parking, { min: 0, max: 1 }) - ) { - errors.parking = 'Should be an integer between 0 and 1'; - } - - if (queryParams.quiet && !isInt(queryParams.quiet, { min: 0, max: 1 })) { - errors.quiet = 'Should be an integer between 0 and 1'; - } - - if (queryParams.ramp && !isInt(queryParams.ramp, { min: 0, max: 1 })) { - errors.ramp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.secondEntry && - !isInt(queryParams.secondEntry, { min: 0, max: 1 }) - ) { - errors.secondEntry = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.spacious && - !isInt(queryParams.spacious, { min: 0, max: 1 }) - ) { - errors.spacious = 'Should be an integer between 0 and 1'; - } - - if (queryParams.steps && !isInt(queryParams.steps, { min: 0, max: 3 })) { - errors.steps = 'Should be an integer between 0 and 3'; - } - - if (queryParams.team && !isMongoId(queryParams.team)) { - errors.team = 'Should be a valid Id'; - } - - if (queryParams.user && !isMongoId(queryParams.user)) { - errors.user = 'Should be a valid Id'; - } - - if (queryParams.venue && !isMongoId(queryParams.venue)) { - errors.venue = 'Should be a valid Id'; - } - - if ( - queryParams.wellLit && - !isInt(queryParams.wellLit, { min: 0, max: 1 }) - ) { - errors.wellLit = 'Should be an integer between 0 and 1'; - } - - // - // new expanded fields - // - if ( - queryParams.hasPermanentRamp && - !isInt(queryParams.hasPermanentRamp, { min: 0, max: 1 }) - ) { - errors.hasPermanentRamp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasPortableRamp && - !isInt(queryParams.hasPortableRamp, { min: 0, max: 1 }) - ) { - errors.hasPortableRamp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasWideEntrance && - !isInt(queryParams.hasWideEntrance, { min: 0, max: 1 }) - ) { - errors.hasWideEntrance = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasAccessibleTableHeight && - !isInt(queryParams.hasAccessibleTableHeight, { min: 0, max: 1 }) - ) { - errors.hasAccessibleTableHeight = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasAccessibleElevator && - !isInt(queryParams.hasAccessibleElevator, { min: 0, max: 1 }) - ) { - errors.hasAccessibleElevator = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasInteriorRamp && - !isInt(queryParams.hasInteriorRamp, { min: 0, max: 1 }) - ) { - errors.hasInteriorRamp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasSwingOutDoor && - !isInt(queryParams.hasSwingOutDoor, { min: 0, max: 1 }) - ) { - errors.hasSwingOutDoor = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasLargeStall && - !isInt(queryParams.hasLargeStall, { min: 0, max: 1 }) - ) { - errors.hasLargeStall = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasSupportAroundToilet && - !isInt(queryParams.hasSupportAroundToilet, { min: 0, max: 1 }) - ) { - errors.hasSupportAroundToilet = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasLoweredSinks && - !isInt(queryParams.hasLoweredSinks, { min: 0, max: 1 }) - ) { - errors.hasLoweredSinks = 'Should be an integer between 0 and 1'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); +const { isInt, isMongoId } = require('validator'); + +module.exports = { + validateCreateEditReview(data) { + const errors = {}; + + // + // new expanded fields + // + if ( + typeof data.hasPermanentRamp !== 'undefined' && + typeof data.hasPermanentRamp !== 'boolean' + ) { + errors.hasPermanentRamp = 'Should be a boolean'; + } + + if ( + typeof data.hasPortableRamp !== 'undefined' && + typeof data.hasPortableRamp !== 'boolean' + ) { + errors.hasPortableRamp = 'Should be a boolean'; + } + + if ( + typeof data.hasWideEntrance !== 'undefined' && + typeof data.hasWideEntrance !== 'boolean' + ) { + errors.hasWideEntrance = 'Should be a boolean'; + } + + if ( + typeof data.hasAccessibleTableHeight !== 'undefined' && + typeof data.hasAccessibleTableHeight !== 'boolean' + ) { + errors.hasAccessibleTableHeight = 'Should be a boolean'; + } + + if ( + typeof data.hasAccessibleElevator !== 'undefined' && + typeof data.hasAccessibleElevator !== 'boolean' + ) { + errors.hasAccessibleElevator = 'Should be a boolean'; + } + + if ( + typeof data.hasInteriorRamp !== 'undefined' && + typeof data.hasInteriorRamp !== 'boolean' + ) { + errors.hasInteriorRamp = 'Should be a boolean'; + } + + if ( + typeof data.hasSwingOutDoor !== 'undefined' && + typeof data.hasSwingOutDoor !== 'boolean' + ) { + errors.hasSwingOutDoor = 'Should be a boolean'; + } + + if ( + typeof data.hasLargeStall !== 'undefined' && + typeof data.hasLargeStall !== 'boolean' + ) { + errors.hasLargeStall = 'Should be a boolean'; + } + + if ( + typeof data.hasSupportAroundToilet !== 'undefined' && + typeof data.hasSupportAroundToilet !== 'boolean' + ) { + errors.hasSupportAroundToilet = 'Should be a boolean'; + } + + if ( + typeof data.hasLoweredSinks !== 'undefined' && + typeof data.hasLoweredSinks !== 'boolean' + ) { + errors.hasLoweredSinks = 'Should be a boolean'; + } + + /* + *interiorScore + if (typeof data.interiorScore !== 'undefined') { + if (typeof data.interiorScore !== 'number') { + errors.interiorScore = 'Should be a number'; + } else if (data.interiorScore < 1 || data.interiorScore > 7) { + //Remove required interiorScore + //errors.interiorScore = 'Should be between 1 and 7'; + } + } + */ + + // + //original fields + // + if ( + typeof data.allowsGuideDog !== 'undefined' && + typeof data.allowsGuideDog !== 'boolean' + ) { + errors.allowsGuideDog = 'Should be a boolean'; + } + + /* + * bathroomScore + if (typeof data.bathroomScore !== 'undefined') { + if (typeof data.bathroomScore !== 'number') { + errors.bathroomScore = 'Should be a number'; + } else if (data.bathroomScore < 1 || data.bathroomScore > 4) { + //Remove required entryScore + //errors.bathroomScore = 'Should be between 1 and 4'; + } + } + */ + + if (data.comments && typeof data.comments !== 'string') { + errors.comments = 'Should be a string'; + } + + /* + * entryScore + if (typeof data.entryScore === 'undefined') { + //Remove required entryScore + //errors.entryScore = 'Is required'; + } else if (typeof data.entryScore !== 'number') { + errors.entryScore = 'Should be a number'; + } else if (data.entryScore < 1 || data.entryScore > 9) { + //Remove required entryScore + //errors.entryScore = 'Should be between 1 and 9'; + } + */ + + if (data.event) { + if (typeof data.event !== 'string') { + errors.event = 'Should be a string'; + } else if (!isMongoId(data.event)) { + errors.event = 'Should be a valid id'; + } + } + + if ( + typeof data.hasParking !== 'undefined' && + typeof data.hasParking !== 'boolean' + ) { + errors.hasParking = 'Should be a boolean'; + } + + if ( + typeof data.hasSecondEntry !== 'undefined' && + typeof data.hasSecondEntry !== 'boolean' + ) { + errors.hasSecondEntry = 'Should be a boolean'; + } + + if ( + typeof data.hasWellLit !== 'undefined' && + typeof data.hasWellLit !== 'boolean' + ) { + errors.hasWellLit = 'Should be a boolean'; + } + + if ( + typeof data.isQuiet !== 'undefined' && + typeof data.isQuiet !== 'boolean' + ) { + errors.isQuiet = 'Should be a boolean'; + } + + if ( + typeof data.isSpacious !== 'undefined' && + typeof data.isSpacious !== 'boolean' + ) { + errors.isSpacious = 'Should be a boolean'; + } + + if (typeof data.photo !== 'undefined' && typeof data.photo !== 'string') { + errors.photo = 'Should be a string'; + } + + if (!data.place) { + errors.place = 'Is required'; + } else if (typeof data.place !== 'string') { + errors.place = 'Should be a string'; + } + + if (typeof data.steps !== 'undefined') { + if (typeof data.steps !== 'number') { + errors.steps = 'Should be a number'; + } else if (data.steps < 0 || data.steps > 3) { + errors.steps = 'Should be between 0 and 3'; + } + } + + if (data.team) { + if (typeof data.team !== 'string') { + errors.team = 'Should be a string'; + } else if (!isMongoId(data.team)) { + errors.team = 'Should be a valid id'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListReviews(queryParams) { + const errors = {}; + + //Remove bathroomScore validation + if (queryParams.bathroomScore) { + /* + const limits = queryParams.bathroomScore.split(','); + + if (limits.length !== 2) { + errors.bathroomScore = 'Should be two integers split by a comma'; + } else if ( + !isInt(limits[0], { min: 1, max: 4 }) || + !isInt(limits[1], { min: 1, max: 4 }) + ) { + errors.bathroomScore = 'Both should be integers between 1 and 4'; + } + */ + } + + //Remove entryScore validation + if (queryParams.entryScore) { + /* + const limits = queryParams.entryScore.split(','); + + if (limits.length !== 2) { + errors.entryScore = 'Should be two integers split by a comma'; + } else if ( + !isInt(limits[0], { min: 1, max: 9 }) || + !isInt(limits[1], { min: 1, max: 9 }) + ) { + errors.entryScore = 'Both should be integers between 1 and 9'; + } + */ + } + + if (queryParams.event && !isMongoId(queryParams.event)) { + errors.event = 'Should be a valid Id'; + } + + if ( + queryParams.guideDog && + !isInt(queryParams.guideDog, { min: 0, max: 1 }) + ) { + errors.guideDog = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.parking && + !isInt(queryParams.parking, { min: 0, max: 1 }) + ) { + errors.parking = 'Should be an integer between 0 and 1'; + } + + if (queryParams.quiet && !isInt(queryParams.quiet, { min: 0, max: 1 })) { + errors.quiet = 'Should be an integer between 0 and 1'; + } + + if (queryParams.ramp && !isInt(queryParams.ramp, { min: 0, max: 1 })) { + errors.ramp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.secondEntry && + !isInt(queryParams.secondEntry, { min: 0, max: 1 }) + ) { + errors.secondEntry = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.spacious && + !isInt(queryParams.spacious, { min: 0, max: 1 }) + ) { + errors.spacious = 'Should be an integer between 0 and 1'; + } + + if (queryParams.steps && !isInt(queryParams.steps, { min: 0, max: 3 })) { + errors.steps = 'Should be an integer between 0 and 3'; + } + + if (queryParams.team && !isMongoId(queryParams.team)) { + errors.team = 'Should be a valid Id'; + } + + if (queryParams.user && !isMongoId(queryParams.user)) { + errors.user = 'Should be a valid Id'; + } + + if (queryParams.venue && !isMongoId(queryParams.venue)) { + errors.venue = 'Should be a valid Id'; + } + + if ( + queryParams.wellLit && + !isInt(queryParams.wellLit, { min: 0, max: 1 }) + ) { + errors.wellLit = 'Should be an integer between 0 and 1'; + } + + // + // new expanded fields + // + if ( + queryParams.hasPermanentRamp && + !isInt(queryParams.hasPermanentRamp, { min: 0, max: 1 }) + ) { + errors.hasPermanentRamp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasPortableRamp && + !isInt(queryParams.hasPortableRamp, { min: 0, max: 1 }) + ) { + errors.hasPortableRamp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasWideEntrance && + !isInt(queryParams.hasWideEntrance, { min: 0, max: 1 }) + ) { + errors.hasWideEntrance = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasAccessibleTableHeight && + !isInt(queryParams.hasAccessibleTableHeight, { min: 0, max: 1 }) + ) { + errors.hasAccessibleTableHeight = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasAccessibleElevator && + !isInt(queryParams.hasAccessibleElevator, { min: 0, max: 1 }) + ) { + errors.hasAccessibleElevator = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasInteriorRamp && + !isInt(queryParams.hasInteriorRamp, { min: 0, max: 1 }) + ) { + errors.hasInteriorRamp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasSwingOutDoor && + !isInt(queryParams.hasSwingOutDoor, { min: 0, max: 1 }) + ) { + errors.hasSwingOutDoor = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasLargeStall && + !isInt(queryParams.hasLargeStall, { min: 0, max: 1 }) + ) { + errors.hasLargeStall = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasSupportAroundToilet && + !isInt(queryParams.hasSupportAroundToilet, { min: 0, max: 1 }) + ) { + errors.hasSupportAroundToilet = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasLoweredSinks && + !isInt(queryParams.hasLoweredSinks, { min: 0, max: 1 }) + ) { + errors.hasLoweredSinks = 'Should be an integer between 0 and 1'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/reviews/vote-review.js b/src/routes/reviews/vote-review.js index dbd8b6c..e3e9472 100644 --- a/src/routes/reviews/vote-review.js +++ b/src/routes/reviews/vote-review.js @@ -1,49 +1,49 @@ -const moment = require('moment'); - -const { Review } = require('../../models/review'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at vote-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - let addVote = true; - - if (review.voters.find(v => v.toString() === req.user.id)) { - review.voters = review.voters.filter(v => v.toString() !== req.user.id); - addVote = false; - } else { - review.voters = [...review.voters, req.user.id]; - } - - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - console.log(`Review ${review.id} failed to be updated at vote-review`); - return next(err); - } - - return res - .status(200) - .json({ general: addVote ? 'One more vote' : 'One less vote' }); -}; +const moment = require('moment'); + +const { Review } = require('../../models/review'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at vote-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + let addVote = true; + + if (review.voters.find((v) => v.toString() === req.user.id)) { + review.voters = review.voters.filter((v) => v.toString() !== req.user.id); + addVote = false; + } else { + review.voters = [...review.voters, req.user.id]; + } + + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + console.log(`Review ${review.id} failed to be updated at vote-review`); + return next(err); + } + + return res + .status(200) + .json({ general: addVote ? 'One more vote' : 'One less vote' }); +}; diff --git a/src/routes/teams/create-team.js b/src/routes/teams/create-team.js index a40dc19..799bdfe 100644 --- a/src/routes/teams/create-team.js +++ b/src/routes/teams/create-team.js @@ -1,93 +1,93 @@ -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); - -const { validateCreateTeam } = require('./validations'); - -module.exports = async (req, res, next) => { - const data = { - avatar: req.body.avatar, - description: req.body.description, - name: req.body.name - }; - - const { errors, isValid } = validateCreateTeam(data); - if (!isValid) return res.status(400).json(errors); - - if (data.avatar) { - let avatar; - try { - avatar = await Photo.findOne({ url: data.avatar }); - } catch (err) { - console.log(`Avatar ${data.avatar} failed to be found at create-team`); - return next(err); - } - - if (!avatar) { - return res.status(404).json({ avatar: 'Not found' }); - } - } - - data.managers = [req.user.id]; - - data.name = cleanSpaces(data.name); - - let repeatedTeam; - try { - repeatedTeam = await Team.findOne({ name: data.name, isArchived: false }); - } catch (err) { - console.log(`Team ${data.name} failed to be found at create-team`); - return next(err); - } - - if (repeatedTeam) { - return res.status(400).json({ name: 'Is already taken' }); - } - - let team; - try { - team = await Team.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Team ${ - data.name - } failed to be created at create-team.\nData: ${JSON.stringify(data)}` - ); - return next(err); - } - - req.user.teams = [...req.user.teams, team.id]; - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at create-team`); - return next(err); - } - - const dataResponse = { - id: team.id, - avatar: team.avatar, - description: team.description, - managers: [ - { - id: req.user.id, - avatar: req.user.avatar, - name: `${req.user.firstName} ${req.user.lastName}` - } - ], - name: team.name - }; - - return res.status(201).json(dataResponse); -}; +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { Team } = require('../../models/team'); + +const { validateCreateTeam } = require('./validations'); + +module.exports = async (req, res, next) => { + const data = { + avatar: req.body.avatar, + description: req.body.description, + name: req.body.name + }; + + const { errors, isValid } = validateCreateTeam(data); + if (!isValid) return res.status(400).json(errors); + + if (data.avatar) { + let avatar; + try { + avatar = await Photo.findOne({ url: data.avatar }); + } catch (err) { + console.log(`Avatar ${data.avatar} failed to be found at create-team`); + return next(err); + } + + if (!avatar) { + return res.status(404).json({ avatar: 'Not found' }); + } + } + + data.managers = [req.user.id]; + + data.name = cleanSpaces(data.name); + + let repeatedTeam; + try { + repeatedTeam = await Team.findOne({ name: data.name, isArchived: false }); + } catch (err) { + console.log(`Team ${data.name} failed to be found at create-team`); + return next(err); + } + + if (repeatedTeam) { + return res.status(400).json({ name: 'Is already taken' }); + } + + let team; + try { + team = await Team.create(data); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Team ${ + data.name + } failed to be created at create-team.\nData: ${JSON.stringify(data)}` + ); + return next(err); + } + + req.user.teams = [...req.user.teams, team.id]; + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at create-team`); + return next(err); + } + + const dataResponse = { + id: team.id, + avatar: team.avatar, + description: team.description, + managers: [ + { + id: req.user.id, + avatar: req.user.avatar, + name: `${req.user.firstName} ${req.user.lastName}` + } + ], + name: team.name + }; + + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/teams/delete-team.js b/src/routes/teams/delete-team.js index 0bf3431..912b7a1 100644 --- a/src/routes/teams/delete-team.js +++ b/src/routes/teams/delete-team.js @@ -1,115 +1,115 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at delete-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - if ( - !team.managers.find(m => m.toString() === req.user.id) && - !req.user.isAdmin - ) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - let archiveTeam = false; - - if (team.events && team.events.length > 0) { - const teamEventsPromises = team.events.map(e => - Event.findOne({ _id: e.toString() }) - ); - - let teamEvents; - try { - teamEvents = await Promise.all(teamEventsPromises); - } catch (err) { - console.log('A team event failed to be found at delete-team'); - return next(err); - } - - for (const event of teamEvents) { - const endDate = moment(event.endDate).utc(); - const endOfToday = moment.utc().endOf('day'); - if (endDate.isBefore(endOfToday)) { - event.teams = event.teams.filter(t => t.toString() !== team.id); - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log(`Event ${event.id} failed to be updated at delete-team`); - return next(err); - } - } else { - archiveTeam = true; - } - } - } - - const teamMembersPromises = team.members.map(m => - User.findOne({ _id: m.toString() }) - ); - - let teamMembers; - try { - teamMembers = await Promise.all(teamMembersPromises); - } catch (err) { - console.log('A team member failed to be found at delete-team'); - return next(err); - } - - for (const member of teamMembers) { - member.teams = member.teams.filter(t => t.toString() !== team.id); - member.updatedAt = moment.utc().toDate(); - - try { - await member.save(); - } catch (err) { - console.log(`Member ${member.id} failed to be updated at delete-team`); - return next(err); - } - } - - if (archiveTeam) { - team.isArchived = true; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at delete-team`); - return next(err); - } - } else { - try { - await team.remove(); - } catch (err) { - console.log(`Team ${team.id} failed to be removed at delete-team`); - return next(err); - } - } - - return res.status(204).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at delete-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + if ( + !team.managers.find((m) => m.toString() === req.user.id) && + !req.user.isAdmin + ) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + let archiveTeam = false; + + if (team.events && team.events.length > 0) { + const teamEventsPromises = team.events.map((e) => + Event.findOne({ _id: e.toString() }) + ); + + let teamEvents; + try { + teamEvents = await Promise.all(teamEventsPromises); + } catch (err) { + console.log('A team event failed to be found at delete-team'); + return next(err); + } + + for (const event of teamEvents) { + const endDate = moment(event.endDate).utc(); + const endOfToday = moment.utc().endOf('day'); + if (endDate.isBefore(endOfToday)) { + event.teams = event.teams.filter((t) => t.toString() !== team.id); + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log(`Event ${event.id} failed to be updated at delete-team`); + return next(err); + } + } else { + archiveTeam = true; + } + } + } + + const teamMembersPromises = team.members.map((m) => + User.findOne({ _id: m.toString() }) + ); + + let teamMembers; + try { + teamMembers = await Promise.all(teamMembersPromises); + } catch (err) { + console.log('A team member failed to be found at delete-team'); + return next(err); + } + + for (const member of teamMembers) { + member.teams = member.teams.filter((t) => t.toString() !== team.id); + member.updatedAt = moment.utc().toDate(); + + try { + await member.save(); + } catch (err) { + console.log(`Member ${member.id} failed to be updated at delete-team`); + return next(err); + } + } + + if (archiveTeam) { + team.isArchived = true; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at delete-team`); + return next(err); + } + } else { + try { + await team.remove(); + } catch (err) { + console.log(`Team ${team.id} failed to be removed at delete-team`); + return next(err); + } + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/teams/edit-team.js b/src/routes/teams/edit-team.js index 0afd345..dbbedb4 100644 --- a/src/routes/teams/edit-team.js +++ b/src/routes/teams/edit-team.js @@ -1,205 +1,205 @@ -const { difference, intersection } = require('lodash'); -const moment = require('moment'); - -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateEditTeam } = require('./validations'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at edit-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - if ( - !team.managers.find(m => m.toString() === req.user.id) && - !req.user.isAdmin - ) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const data = { - avatar: req.body.avatar, - description: req.body.description, - managers: req.body.managers, - members: req.body.members, - name: req.body.name - }; - const { errors, isValid } = validateEditTeam(data); - if (!isValid) return res.status(400).json(errors); - - if ( - data.avatar && - !data.avatar.includes('default') && - data.avatar !== team.avatar - ) { - let avatar; - try { - avatar = await Photo.findOne({ url: data.avatar }); - } catch (err) { - console.log(`Avatar ${data.avatar} failed to be found at edit-team`); - return next(err); - } - - if (!avatar) { - return res.status(404).json({ avatar: 'Not found' }); - } - - team.avatar = data.avatar; - } else if (data.avatar === '') { - team.avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/teams/avatars/default.png`; - } - - team.description = data.description || team.description; - - if (data.managers) { - let managersToAdd = []; - let managersToRemove = []; - - data.managers.forEach(m => { - if (m.startsWith('-')) { - managersToRemove = [...managersToRemove, m.substring(1)]; - } else { - managersToAdd = [...managersToAdd, m]; - } - }); - - const teamManagers = team.managers.map(m => m.toString()); - - managersToAdd = [...new Set(difference(managersToAdd, teamManagers))]; - if (managersToAdd.length > 0) { - const teamMembers = team.members.map(m => m.toString()); - const notMember = managersToAdd.find(m => !teamMembers.includes(m)); - - if (notMember) { - return res - .status(400) - .json({ managers: `User ${notMember} is not a member of this team` }); - } - - team.managers = [...teamManagers, ...managersToAdd]; - team.members = team.members.filter( - m => !managersToAdd.includes(m.toString()) - ); - } - - managersToRemove = [ - ...new Set(intersection(managersToRemove, teamManagers)) - ]; - if (managersToRemove.length === team.managers.length) { - return res - .status(400) - .json({ managers: 'Should not remove all managers' }); - } - - team.managers = team.managers.filter( - m => !managersToRemove.includes(m.toString()) - ); - const teamMembers = team.members.map(m => m.toString()); - team.members = [...teamMembers, ...managersToRemove]; - } - - if (data.members) { - const teamMembers = team.members.map(m => m.toString()); - let membersToRemove = data.members.map(m => m.substring(1)); - membersToRemove = [...new Set(intersection(membersToRemove, teamMembers))]; - - const getMembers = membersToRemove.map(m => - User.find({ _id: m, isArchived: false }) - ); - let members; - try { - members = await Promise.all(getMembers); - } catch (err) { - console.log(`Members failed to be found at edit-team`); - return next(err); - } - - const updateMembers = members.map((m, i) => { - m[i].teams = m[i].teams.filter(t => t.toString() !== team.id); - return m[i].save(); - }); - - try { - await Promise.all(updateMembers); - } catch (err) { - console.log(`Members failed to be updated at edit-team`); - return next(err); - } - - team.members = team.members.filter( - m => !membersToRemove.includes(m.toString()) - ); - } - - if (data.name) { - const teamName = cleanSpaces(data.name); - - if (teamName !== team.name) { - let repeatedTeam; - try { - repeatedTeam = await Team.findOne({ - name: teamName, - isArchived: false - }); - } catch (err) { - console.log(`Team ${teamName} failed to be found at edit-team`); - return next(err); - } - - if (repeatedTeam) { - return res.status(400).json({ name: 'Is already taken' }); - } - - team.name = teamName; - } - } - - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Team ${team.id} failed to be updated at edit-team`); - return next(err); - } - - const dataResponse = { - id: team.id, - avatar: team.avatar, - description: team.description, - managers: team.managers, - members: team.members, - name: team.name - }; - - return res.status(200).json(dataResponse); -}; +const { difference, intersection } = require('lodash'); +const moment = require('moment'); + +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const { validateEditTeam } = require('./validations'); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at edit-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + if ( + !team.managers.find((m) => m.toString() === req.user.id) && + !req.user.isAdmin + ) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const data = { + avatar: req.body.avatar, + description: req.body.description, + managers: req.body.managers, + members: req.body.members, + name: req.body.name + }; + const { errors, isValid } = validateEditTeam(data); + if (!isValid) return res.status(400).json(errors); + + if ( + data.avatar && + !data.avatar.includes('default') && + data.avatar !== team.avatar + ) { + let avatar; + try { + avatar = await Photo.findOne({ url: data.avatar }); + } catch (err) { + console.log(`Avatar ${data.avatar} failed to be found at edit-team`); + return next(err); + } + + if (!avatar) { + return res.status(404).json({ avatar: 'Not found' }); + } + + team.avatar = data.avatar; + } else if (data.avatar === '') { + team.avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/teams/avatars/default.png`; + } + + team.description = data.description || team.description; + + if (data.managers) { + let managersToAdd = []; + let managersToRemove = []; + + data.managers.forEach((m) => { + if (m.startsWith('-')) { + managersToRemove = [...managersToRemove, m.substring(1)]; + } else { + managersToAdd = [...managersToAdd, m]; + } + }); + + const teamManagers = team.managers.map((m) => m.toString()); + + managersToAdd = [...new Set(difference(managersToAdd, teamManagers))]; + if (managersToAdd.length > 0) { + const teamMembers = team.members.map((m) => m.toString()); + const notMember = managersToAdd.find((m) => !teamMembers.includes(m)); + + if (notMember) { + return res + .status(400) + .json({ managers: `User ${notMember} is not a member of this team` }); + } + + team.managers = [...teamManagers, ...managersToAdd]; + team.members = team.members.filter( + (m) => !managersToAdd.includes(m.toString()) + ); + } + + managersToRemove = [ + ...new Set(intersection(managersToRemove, teamManagers)) + ]; + if (managersToRemove.length === team.managers.length) { + return res + .status(400) + .json({ managers: 'Should not remove all managers' }); + } + + team.managers = team.managers.filter( + (m) => !managersToRemove.includes(m.toString()) + ); + const teamMembers = team.members.map((m) => m.toString()); + team.members = [...teamMembers, ...managersToRemove]; + } + + if (data.members) { + const teamMembers = team.members.map((m) => m.toString()); + let membersToRemove = data.members.map((m) => m.substring(1)); + membersToRemove = [...new Set(intersection(membersToRemove, teamMembers))]; + + const getMembers = membersToRemove.map((m) => + User.find({ _id: m, isArchived: false }) + ); + let members; + try { + members = await Promise.all(getMembers); + } catch (err) { + console.log(`Members failed to be found at edit-team`); + return next(err); + } + + const updateMembers = members.map((m, i) => { + m[i].teams = m[i].teams.filter((t) => t.toString() !== team.id); + return m[i].save(); + }); + + try { + await Promise.all(updateMembers); + } catch (err) { + console.log(`Members failed to be updated at edit-team`); + return next(err); + } + + team.members = team.members.filter( + (m) => !membersToRemove.includes(m.toString()) + ); + } + + if (data.name) { + const teamName = cleanSpaces(data.name); + + if (teamName !== team.name) { + let repeatedTeam; + try { + repeatedTeam = await Team.findOne({ + name: teamName, + isArchived: false + }); + } catch (err) { + console.log(`Team ${teamName} failed to be found at edit-team`); + return next(err); + } + + if (repeatedTeam) { + return res.status(400).json({ name: 'Is already taken' }); + } + + team.name = teamName; + } + } + + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Team ${team.id} failed to be updated at edit-team`); + return next(err); + } + + const dataResponse = { + id: team.id, + avatar: team.avatar, + description: team.description, + managers: team.managers, + members: team.members, + name: team.name + }; + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/teams/get-team.js b/src/routes/teams/get-team.js index ea86094..9f3f0ca 100644 --- a/src/routes/teams/get-team.js +++ b/src/routes/teams/get-team.js @@ -1,144 +1,144 @@ -const mongoose = require('mongoose'); - -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - const teamIdObj = mongoose.Types.ObjectId(teamId); - let team; - try { - team = await Team.aggregate([ - { - $match: { _id: teamIdObj } - }, - { - $lookup: { - from: 'users', - let: { members: '$members' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$members'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1, - username: 1 - } - } - ], - as: 'members' - } - }, - { - $lookup: { - from: 'users', - let: { managers: '$managers' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$managers'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1, - username: 1 - } - } - ], - as: 'managers' - } - }, - { - $lookup: { - from: 'events', - let: { events: '$events' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$events'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - endDate: 1, - name: 1, - poster: 1, - startDate: 1 - } - } - ], - as: 'events' - } - }, - { - $lookup: { - from: 'teams', - let: { reviewsAmount: '$reviewsAmount' }, - pipeline: [ - { - $match: { - $expr: { - $gt: ['$reviewsAmount', '$$reviewsAmount'] - } - } - }, - { - $count: 'ranking' - } - ], - as: 'ranking' - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - description: 1, - reviewsAmount: 1, - name: 1, - members: 1, - events: 1, - managers: 1, - ranking: 1 - } - } - ]); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at get-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - const dataResponse = Object.assign({}, team[0], { - ranking: team[0].ranking.length ? team[0].ranking[0].ranking + 1 : 1 - }); - return res.status(200).json(dataResponse); -}; +const mongoose = require('mongoose'); + +const { Team } = require('../../models/team'); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + const teamIdObj = new mongoose.Types.ObjectId(teamId); + let team; + try { + team = await Team.aggregate([ + { + $match: { _id: teamIdObj } + }, + { + $lookup: { + from: 'users', + let: { members: '$members' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$members'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1, + username: 1 + } + } + ], + as: 'members' + } + }, + { + $lookup: { + from: 'users', + let: { managers: '$managers' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$managers'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1, + username: 1 + } + } + ], + as: 'managers' + } + }, + { + $lookup: { + from: 'events', + let: { events: '$events' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$events'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + endDate: 1, + name: 1, + poster: 1, + startDate: 1 + } + } + ], + as: 'events' + } + }, + { + $lookup: { + from: 'teams', + let: { reviewsAmount: '$reviewsAmount' }, + pipeline: [ + { + $match: { + $expr: { + $gt: ['$reviewsAmount', '$$reviewsAmount'] + } + } + }, + { + $count: 'ranking' + } + ], + as: 'ranking' + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + description: 1, + reviewsAmount: 1, + name: 1, + members: 1, + events: 1, + managers: 1, + ranking: 1 + } + } + ]); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at get-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + const dataResponse = Object.assign({}, team[0], { + ranking: team[0].ranking.length ? team[0].ranking[0].ranking + 1 : 1 + }); + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/teams/index.js b/src/routes/teams/index.js index 8ffc659..83b4f3e 100644 --- a/src/routes/teams/index.js +++ b/src/routes/teams/index.js @@ -1,23 +1,23 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createTeam = require('./create-team'); -const deleteTeam = require('./delete-team'); -const editTeam = require('./edit-team'); -const getTeam = require('./get-team'); -const joinTeam = require('./join-team'); -const leaveTeam = require('./leave-team'); -const listTeams = require('./list-teams'); - -const router = new express.Router(); - -router.get('', isAuthenticated({ isOptional: true }), listTeams); -router.post('', isAuthenticated({ isOptional: false }), createTeam); -router.get('/:teamId', getTeam); -router.put('/:teamId', isAuthenticated({ isOptional: false }), editTeam); -router.delete('/:teamId', isAuthenticated({ isOptional: false }), deleteTeam); -router.post('/:teamId/join', isAuthenticated({ isOptional: false }), joinTeam); -router.put('/:teamId/leave', isAuthenticated({ isOptional: false }), leaveTeam); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const createTeam = require('./create-team'); +const deleteTeam = require('./delete-team'); +const editTeam = require('./edit-team'); +const getTeam = require('./get-team'); +const joinTeam = require('./join-team'); +const leaveTeam = require('./leave-team'); +const listTeams = require('./list-teams'); + +const router = new express.Router(); + +router.get('', isAuthenticated({ isOptional: true }), listTeams); +router.post('', isAuthenticated({ isOptional: false }), createTeam); +router.get('/:teamId', getTeam); +router.put('/:teamId', isAuthenticated({ isOptional: false }), editTeam); +router.delete('/:teamId', isAuthenticated({ isOptional: false }), deleteTeam); +router.post('/:teamId/join', isAuthenticated({ isOptional: false }), joinTeam); +router.put('/:teamId/leave', isAuthenticated({ isOptional: false }), leaveTeam); + +module.exports = router; diff --git a/src/routes/teams/join-team.js b/src/routes/teams/join-team.js index caf65ea..c2de2e4 100644 --- a/src/routes/teams/join-team.js +++ b/src/routes/teams/join-team.js @@ -1,98 +1,98 @@ -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at join-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - const eventMembers = team.members.map(m => m.toString()); - if (eventMembers.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a member in this team' }); - } - - const eventManagers = team.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a member in this team' }); - } - - let petition; - try { - petition = await Petition.findOne({ - team: team.id, - sender: req.user.id, - type: 'request-user-team' - }); - } catch (err) { - console.log( - `Petition from user ${req.user.id} to team ${ - team.id - } failed to be found at join-team` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'You already have a pending petition with this team' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log(`Petition ${petition.id} failed to be removed at join-team`); - return next(err); - } - } - - const petitionData = { - team: team.id, - sender: req.user.id, - type: 'request-user-team' - }; - try { - await Petition.create(petitionData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Petition failed to be created at join-team.\nData: ${JSON.stringify( - petitionData - )}` - ); - return next(err); - } - - return res.status(200).json({ general: 'Requested' }); -}; +const { Petition } = require('../../models/petition'); +const { Team } = require('../../models/team'); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at join-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + const eventMembers = team.members.map((m) => m.toString()); + if (eventMembers.includes(req.user.id)) { + return res + .status(400) + .json({ general: 'You already are a member in this team' }); + } + + const eventManagers = team.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + return res + .status(400) + .json({ general: 'You already are a member in this team' }); + } + + let petition; + try { + petition = await Petition.findOne({ + team: team.id, + sender: req.user.id, + type: 'request-user-team' + }); + } catch (err) { + console.log( + `Petition from user ${req.user.id} to team ${ + team.id + } failed to be found at join-team` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'You already have a pending petition with this team' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log(`Petition ${petition.id} failed to be removed at join-team`); + return next(err); + } + } + + const petitionData = { + team: team.id, + sender: req.user.id, + type: 'request-user-team' + }; + try { + await Petition.create(petitionData); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Petition failed to be created at join-team.\nData: ${JSON.stringify( + petitionData + )}` + ); + return next(err); + } + + return res.status(200).json({ general: 'Requested' }); +}; diff --git a/src/routes/teams/leave-team.js b/src/routes/teams/leave-team.js index 8a9a954..1311c88 100644 --- a/src/routes/teams/leave-team.js +++ b/src/routes/teams/leave-team.js @@ -1,59 +1,59 @@ -const moment = require('moment'); - -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at leave-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - if (team.managers.find(m => m.toString() === req.user.id)) { - team.managers = team.managers.filter(m => m.toString() !== req.user.id); - - if (team.managers.length === 0) { - return res.status(400).json({ - general: 'You cannot leave because you are the only manager' - }); - } - } else if (team.members.find(m => m.toString() === req.user.id)) { - team.members = team.members.filter(m => m.toString() !== req.user.id); - } else { - return res.status(400).json({ general: 'You are not a member' }); - } - - const today = moment.utc(); - team.updatedAt = today.toDate(); - - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at leave-team`); - return next(err); - } - - req.user.teams = req.user.teams.filter(t => t.toString() !== team.id); - req.user.updatedAt = today.toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at leave-team`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Team } = require('../../models/team'); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at leave-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + if (team.managers.find((m) => m.toString() === req.user.id)) { + team.managers = team.managers.filter((m) => m.toString() !== req.user.id); + + if (team.managers.length === 0) { + return res.status(400).json({ + general: 'You cannot leave because you are the only manager' + }); + } + } else if (team.members.find((m) => m.toString() === req.user.id)) { + team.members = team.members.filter((m) => m.toString() !== req.user.id); + } else { + return res.status(400).json({ general: 'You are not a member' }); + } + + const today = moment.utc(); + team.updatedAt = today.toDate(); + + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at leave-team`); + return next(err); + } + + req.user.teams = req.user.teams.filter((t) => t.toString() !== team.id); + req.user.updatedAt = today.toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at leave-team`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/teams/list-teams.js b/src/routes/teams/list-teams.js index a667d81..605bcf6 100644 --- a/src/routes/teams/list-teams.js +++ b/src/routes/teams/list-teams.js @@ -1,104 +1,104 @@ -const mongoose = require('mongoose'); -const { toBoolean } = require('validator'); - -const { Team } = require('../../models/team'); - -const { validateListTeams } = require('./validations'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - - const { errors, isValid } = validateListTeams(queryParams); - if (!isValid) return res.status(400).json(errors); - - const teamsQuery = { isArchived: false }; - - if (queryParams.keywords) { - teamsQuery.$text = { $search: queryParams.keywords }; - } - - if (queryParams.managed) { - if (!req.user) { - return res - .status(400) - .json({ general: 'You cannot use managed filter as anonymous' }); - } - - const managed = toBoolean(queryParams.managed); - if (managed) { - teamsQuery.managers = { $in: [mongoose.Types.ObjectId(req.user.id)] }; - } else { - teamsQuery.managers = { $nin: [mongoose.Types.ObjectId(req.user.id)] }; - } - } - - let sortBy = queryParams.sortBy || '-reviewsAmount'; - let page = queryParams.page ? Number(queryParams.page) - 1 : 0; - const pageLimit = Number(queryParams.pageLimit) || 12; - - let teams; - let total; - try { - [teams, total] = await Promise.all([ - Team.aggregate() - .match(teamsQuery) - .project({ - _id: 0, - id: '$_id', - avatar: 1, - description: 1, - name: 1, - reviewsAmount: 1 - }) - .sort(sortBy) - .skip(page * pageLimit) - .limit(pageLimit), - Team.find(teamsQuery).count() - ]); - } catch (err) { - console.log('Teams failed to be found or count at list-teams'); - return next(err); - } - - const getTeamsRankings = teams.map(t => - Team.find({ reviewsAmount: { $gt: t.reviewsAmount } }).count() - ); - - let teamsRankings; - try { - teamsRankings = await Promise.all(getTeamsRankings); - } catch (err) { - console.log('Teams rankings failed to be count at list-teams'); - return next(err); - } - - teams = teams.map((t, i) => ({ - id: t.id, - avatar: t.avatar, - description: t.description, - name: t.name, - ranking: teamsRankings[i] + 1, - reviewsAmount: t.reviewsAmount - })); - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - return res.status(200).json({ - page: page + 1, - lastPage, - pageLimit, - total, - sortBy, - results: teams - }); -}; +const mongoose = require('mongoose'); +const { toBoolean } = require('validator'); + +const { Team } = require('../../models/team'); + +const { validateListTeams } = require('./validations'); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListTeams(queryParams); + if (!isValid) return res.status(400).json(errors); + + const teamsQuery = { isArchived: false }; + + if (queryParams.keywords) { + teamsQuery.$text = { $search: queryParams.keywords }; + } + + if (queryParams.managed) { + if (!req.user) { + return res + .status(400) + .json({ general: 'You cannot use managed filter as anonymous' }); + } + + const managed = toBoolean(queryParams.managed); + if (managed) { + teamsQuery.managers = { $in: [new mongoose.Types.ObjectId(req.user.id)] }; + } else { + teamsQuery.managers = { $nin: [new mongoose.Types.ObjectId(req.user.id)] }; + } + } + + let sortBy = queryParams.sortBy || '-reviewsAmount'; + let page = queryParams.page ? Number(queryParams.page) - 1 : 0; + const pageLimit = Number(queryParams.pageLimit) || 12; + + let teams; + let total; + try { + [teams, total] = await Promise.all([ + Team.aggregate() + .match(teamsQuery) + .project({ + _id: 0, + id: '$_id', + avatar: 1, + description: 1, + name: 1, + reviewsAmount: 1 + }) + .sort(sortBy) + .skip(page * pageLimit) + .limit(pageLimit), + Team.find(teamsQuery).count() + ]); + } catch (err) { + console.log('Teams failed to be found or count at list-teams'); + return next(err); + } + + const getTeamsRankings = teams.map((t) => + Team.find({ reviewsAmount: { $gt: t.reviewsAmount } }).count() + ); + + let teamsRankings; + try { + teamsRankings = await Promise.all(getTeamsRankings); + } catch (err) { + console.log('Teams rankings failed to be count at list-teams'); + return next(err); + } + + teams = teams.map((t, i) => ({ + id: t.id, + avatar: t.avatar, + description: t.description, + name: t.name, + ranking: teamsRankings[i] + 1, + reviewsAmount: t.reviewsAmount + })); + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + + return res.status(200).json({ + page: page + 1, + lastPage, + pageLimit, + total, + sortBy, + results: teams + }); +}; diff --git a/src/routes/teams/validations.js b/src/routes/teams/validations.js index 045359a..ce1f9b2 100644 --- a/src/routes/teams/validations.js +++ b/src/routes/teams/validations.js @@ -1,134 +1,134 @@ -const { isEmpty } = require('lodash'); -const { isInt, isMongoId } = require('validator'); - -module.exports = { - validateCreateTeam(data) { - const errors = {}; - - if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { - errors.avatar = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (typeof data.name === 'undefined' || data.name === '') { - errors.name = 'Is required'; - } else if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditTeam(data) { - const errors = {}; - - if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { - errors.avatar = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (typeof data.name !== 'undefined') { - if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } else if (data.name === '') { - errors.name = 'Is required'; - } - } - - if (data.managers) { - if (!Array.isArray(data.managers)) { - errors.managers = 'Should be an array'; - } else { - data.managers.some(m => { - if (typeof m !== 'string') { - errors.managers = 'Should only have string values'; - return true; - } else if (!m) { - errors.managers = 'Should not have empty values'; - return true; - } else { - if (m.startsWith('-')) { - m = m.substring(1); - } - - if (!isMongoId(m)) { - errors.managers = `${m} should be an id`; - return true; - } - } - }); - } - } - - if (data.members) { - if (!Array.isArray(data.members)) { - errors.members = 'Should be an array'; - } else { - data.members.some(m => { - if (typeof m !== 'string') { - errors.members = 'Should only have string values'; - return true; - } else if (!m) { - errors.managers = 'Should not have empty values'; - return true; - } else if (!m.startsWith('-')) { - errors.members = `${m} should start with -`; - return true; - } else if (!isMongoId(m.substring(1))) { - errors.members = `${m} should be an id`; - return true; - } - }); - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListTeams(queryParams) { - const errors = {}; - - if ( - queryParams.managed && - queryParams.managed !== '0' && - queryParams.managed !== '1' - ) { - errors.managed = 'Should be 0 or 1'; - } - - const sortOptions = ['name', '-name', 'reviewsAmount', '-reviewsAmount']; - if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { - errors.sortBy = 'Should be a valid sort'; - } - - if (queryParams.page) { - if (!isInt(queryParams.page)) { - errors.page = 'Should be a integer'; - } else if (parseInt(queryParams.page, 10) < 1) { - errors.page = 'Should be a positive integer'; - } - } - - if (queryParams.pageLimit) { - if (!isInt(queryParams.pageLimit)) { - errors.pageLimit = 'Should be a integer'; - } else if (parseInt(queryParams.pageLimit, 10) < 1) { - errors.pageLimit = 'Should be a positive integer'; - } else if (parseInt(queryParams.pageLimit, 10) > 12) { - errors.pageLimit = 'Should be less than 13'; - } - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); +const { isInt, isMongoId } = require('validator'); + +module.exports = { + validateCreateTeam(data) { + const errors = {}; + + if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { + errors.avatar = 'Should be a string'; + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + if (typeof data.name === 'undefined' || data.name === '') { + errors.name = 'Is required'; + } else if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditTeam(data) { + const errors = {}; + + if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { + errors.avatar = 'Should be a string'; + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + if (typeof data.name !== 'undefined') { + if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } else if (data.name === '') { + errors.name = 'Is required'; + } + } + + if (data.managers) { + if (!Array.isArray(data.managers)) { + errors.managers = 'Should be an array'; + } else { + data.managers.some((m) => { + if (typeof m !== 'string') { + errors.managers = 'Should only have string values'; + return true; + } else if (!m) { + errors.managers = 'Should not have empty values'; + return true; + } else { + if (m.startsWith('-')) { + m = m.substring(1); + } + + if (!isMongoId(m)) { + errors.managers = `${m} should be an id`; + return true; + } + } + }); + } + } + + if (data.members) { + if (!Array.isArray(data.members)) { + errors.members = 'Should be an array'; + } else { + data.members.some((m) => { + if (typeof m !== 'string') { + errors.members = 'Should only have string values'; + return true; + } else if (!m) { + errors.managers = 'Should not have empty values'; + return true; + } else if (!m.startsWith('-')) { + errors.members = `${m} should start with -`; + return true; + } else if (!isMongoId(m.substring(1))) { + errors.members = `${m} should be an id`; + return true; + } + }); + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListTeams(queryParams) { + const errors = {}; + + if ( + queryParams.managed && + queryParams.managed !== '0' && + queryParams.managed !== '1' + ) { + errors.managed = 'Should be 0 or 1'; + } + + const sortOptions = ['name', '-name', 'reviewsAmount', '-reviewsAmount']; + if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { + errors.sortBy = 'Should be a valid sort'; + } + + if (queryParams.page) { + if (!isInt(queryParams.page)) { + errors.page = 'Should be a integer'; + } else if (parseInt(queryParams.page, 10) < 1) { + errors.page = 'Should be a positive integer'; + } + } + + if (queryParams.pageLimit) { + if (!isInt(queryParams.pageLimit)) { + errors.pageLimit = 'Should be a integer'; + } else if (parseInt(queryParams.pageLimit, 10) < 1) { + errors.pageLimit = 'Should be a positive integer'; + } else if (parseInt(queryParams.pageLimit, 10) > 12) { + errors.pageLimit = 'Should be less than 13'; + } + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/users/archive-user.js b/src/routes/users/archive-user.js index 46e3f3c..4d19eba 100644 --- a/src/routes/users/archive-user.js +++ b/src/routes/users/archive-user.js @@ -1,101 +1,101 @@ -const moment = require('moment'); - -const { ActivationTicket } = require('../../models/activation-ticket'); -const { PasswordTicket } = require('../../models/password-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at archive-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - if (user.id !== req.user.id && !req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - let activateAccountTicket; - let passwordTicket; - let refreshToken; - try { - [activateAccountTicket, passwordTicket, refreshToken] = await Promise.all([ - ActivationTicket.findOne({ email: user.email }), - PasswordTicket.findOne({ email: user.email }), - RefreshToken.findOne({ userId: user.id }) - ]); - } catch (err) { - console.log( - `Activate account ticket, password ticket or refresh token with email ${ - user.email - } failed to be found at archive-user.` - ); - return next(err); - } - - if (activateAccountTicket) { - try { - await activateAccountTicket.remove(); - } catch (err) { - console.log( - `Activate user ticket with key ${ - activateAccountTicket.key - } failed to be removed at archive-user.` - ); - return next(err); - } - } - - if (passwordTicket) { - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password ticket with key ${ - passwordTicket.key - } failed to be removed at archive-user.` - ); - return next(err); - } - } - - if (refreshToken) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh token with key ${ - refreshToken.key - } failed to be removed at archive-user.` - ); - return next(err); - } - } - - user.isArchived = true; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User with email ${user.email} failed to be updated at archive-user.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { ActivationTicket } = require('../../models/activation-ticket'); +const { PasswordTicket } = require('../../models/password-ticket'); +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User with Id ${userId} failed to be found at archive-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + if (user.id !== req.user.id && !req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + let activateAccountTicket; + let passwordTicket; + let refreshToken; + try { + [activateAccountTicket, passwordTicket, refreshToken] = await Promise.all([ + ActivationTicket.findOne({ email: user.email }), + PasswordTicket.findOne({ email: user.email }), + RefreshToken.findOne({ userId: user.id }) + ]); + } catch (err) { + console.log( + `Activate account ticket, password ticket or refresh token with email ${ + user.email + } failed to be found at archive-user.` + ); + return next(err); + } + + if (activateAccountTicket) { + try { + await activateAccountTicket.remove(); + } catch (err) { + console.log( + `Activate user ticket with key ${ + activateAccountTicket.key + } failed to be removed at archive-user.` + ); + return next(err); + } + } + + if (passwordTicket) { + try { + await passwordTicket.remove(); + } catch (err) { + console.log( + `Password ticket with key ${ + passwordTicket.key + } failed to be removed at archive-user.` + ); + return next(err); + } + } + + if (refreshToken) { + try { + await refreshToken.remove(); + } catch (err) { + console.log( + `Refresh token with key ${ + refreshToken.key + } failed to be removed at archive-user.` + ); + return next(err); + } + } + + user.isArchived = true; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User with email ${user.email} failed to be updated at archive-user.` + ); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/users/block-user.js b/src/routes/users/block-user.js index 6e93c8a..44c88ec 100644 --- a/src/routes/users/block-user.js +++ b/src/routes/users/block-user.js @@ -1,39 +1,39 @@ -const moment = require('moment'); - -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at block-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - user.isBlocked = true; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log(`User with Id ${user.id} failed to be updated at block-user.`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User with Id ${userId} failed to be found at block-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + user.isBlocked = true; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log(`User with Id ${user.id} failed to be updated at block-user.`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/users/change-password.js b/src/routes/users/change-password.js index 13b2391..2c88231 100644 --- a/src/routes/users/change-password.js +++ b/src/routes/users/change-password.js @@ -1,64 +1,64 @@ -const moment = require('moment'); - -const { RefreshToken } = require('../../models/refresh-token'); - -const { validateChangePassword } = require('./validations'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const { errors, isValid } = validateChangePassword(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const oldPassword = req.body.oldPassword; - const password = req.body.password; - - const passwordMatches = req.user.comparePassword(oldPassword); - - if (!passwordMatches) { - return res.status(400).json({ oldPassword: 'Wrong password' }); - } - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ userId: req.user.id }); - } catch (err) { - console.log( - `Refresh Token with userId ${ - req.user.id - } failed to be found at change-password.` - ); - return next(err); - } - - if (refreshToken) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh Token with key ${ - refreshToken.key - } failed to be removed at change-password.` - ); - return next(err); - } - } - - req.user.password = password; - req.user.updatedAt = moment.utc().toDate(); - - try { - req.user.save(); - } catch (err) { - console.log( - `User with Id ${req.user.id} failed to be updated at change-password.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { RefreshToken } = require('../../models/refresh-token'); + +const { validateChangePassword } = require('./validations'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const { errors, isValid } = validateChangePassword(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const oldPassword = req.body.oldPassword; + const password = req.body.password; + + const passwordMatches = req.user.comparePassword(oldPassword); + + if (!passwordMatches) { + return res.status(400).json({ oldPassword: 'Wrong password' }); + } + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ userId: req.user.id }); + } catch (err) { + console.log( + `Refresh Token with userId ${ + req.user.id + } failed to be found at change-password.` + ); + return next(err); + } + + if (refreshToken) { + try { + await refreshToken.remove(); + } catch (err) { + console.log( + `Refresh Token with key ${ + refreshToken.key + } failed to be removed at change-password.` + ); + return next(err); + } + } + + req.user.password = password; + req.user.updatedAt = moment.utc().toDate(); + + try { + req.user.save(); + } catch (err) { + console.log( + `User with Id ${req.user.id} failed to be updated at change-password.` + ); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/users/create-user.js b/src/routes/users/create-user.js index 937fb97..3fb3d2e 100644 --- a/src/routes/users/create-user.js +++ b/src/routes/users/create-user.js @@ -1,153 +1,150 @@ -const crypto = require('crypto'); - -const moment = require('moment'); -const { pick } = require('lodash'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { cleanSpaces } = require('../../helpers'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateCreateUser } = require('./validations'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const { errors, isValid } = validateCreateUser(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const userData = pick(req.body, [ - 'description', - 'disabilities', - 'email', - 'firstName', - 'gender', - 'isSubscribed', - 'lastName', - 'password', - 'phone', - 'showDisabilities', - 'showEmail', - 'showPhone', - 'username', - 'zip' - ]); - userData.firstName = cleanSpaces(userData.firstName); - userData.lastName = cleanSpaces(userData.lastName); - - let usernameSent = true; - - if (!userData.username) { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}`; - usernameSent = false; - } - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - $or: [{ email: userData.email }, { username: userData.username }], - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at create-user.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - for (const user of repeatedUsers) { - if (user.email === userData.email) { - return res.status(400).json({ email: 'Is already taken' }); - } else if (usernameSent && user.username === userData.username) { - return res.status(400).json({ username: 'Is already taken' }); - } - - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at create-user.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - } - - let user; - try { - user = await User.create(userData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `User with email ${userData.email} failed to be created at create-user.` - ); - return next(err); - } - - const refreshTokenData = { - expiresAt: moment - .utc() - .add(14, 'days') - .toDate(), - key: `${user.id}${crypto.randomBytes(40).toString('hex')}`, - userId: user.id - }; - try { - await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token with userId ${ - refreshTokenData.userId - } failed to be created at create-user.` - ); - return next(err); - } - - const dataResponse = pick(user, [ - '_id', - 'description', - 'disabilities', - 'email', - 'firstName', - 'gender', - 'isSubscribed', - 'lastName', - 'phone', - 'showDisabilities', - 'showEmail', - 'showPhone', - 'username', - 'zip' - ]); - return res.status(201).json(dataResponse); -}; +const crypto = require('crypto'); + +const moment = require('moment'); +const { pick } = require('lodash'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +const { cleanSpaces } = require('../../helpers'); +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +const { validateCreateUser } = require('./validations'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const { errors, isValid } = validateCreateUser(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const userData = pick(req.body, [ + 'description', + 'disabilities', + 'email', + 'firstName', + 'gender', + 'isSubscribed', + 'lastName', + 'password', + 'phone', + 'showDisabilities', + 'showEmail', + 'showPhone', + 'username', + 'zip' + ]); + userData.firstName = cleanSpaces(userData.firstName); + userData.lastName = cleanSpaces(userData.lastName); + + let usernameSent = true; + + if (!userData.username) { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}`; + usernameSent = false; + } + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + $or: [{ email: userData.email }, { username: userData.username }], + isArchived: false + }); + } catch (err) { + console.log('Users failed to be found at create-user.'); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + for (const user of repeatedUsers) { + if (user.email === userData.email) { + return res.status(400).json({ email: 'Is already taken' }); + } else if (usernameSent && user.username === userData.username) { + return res.status(400).json({ username: 'Is already taken' }); + } + + let repeatedUser; + do { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}`; + + try { + repeatedUser = await User.findOne({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${ + userData.username + } failed to be found at create-user.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === userData.username); + } + } + + let user; + try { + user = await User.create(userData); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `User with email ${userData.email} failed to be created at create-user.` + ); + return next(err); + } + + const refreshTokenData = { + expiresAt: moment.utc().add(14, 'days').toDate(), + key: `${user.id}${crypto.randomBytes(40).toString('hex')}`, + userId: user.id + }; + try { + await RefreshToken.create(refreshTokenData); + } catch (err) { + console.log( + `Refresh token with userId ${ + refreshTokenData.userId + } failed to be created at create-user.` + ); + return next(err); + } + + const dataResponse = pick(user, [ + '_id', + 'description', + 'disabilities', + 'email', + 'firstName', + 'gender', + 'isSubscribed', + 'lastName', + 'phone', + 'showDisabilities', + 'showEmail', + 'showPhone', + 'username', + 'zip' + ]); + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/users/delete-user.js b/src/routes/users/delete-user.js index 39464d2..401e7e4 100644 --- a/src/routes/users/delete-user.js +++ b/src/routes/users/delete-user.js @@ -1,36 +1,36 @@ -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: true }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Archived user not found' }); - } - - console.log(`User with Id ${userId} failed to be found at delete-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'Archived user not found' }); - } - - try { - await user.remove(); - } catch (err) { - console.log( - `User with email ${user.email} failed to be deleted at delete-user.` - ); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: true }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Archived user not found' }); + } + + console.log(`User with Id ${userId} failed to be found at delete-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'Archived user not found' }); + } + + try { + await user.remove(); + } catch (err) { + console.log( + `User with email ${user.email} failed to be deleted at delete-user.` + ); + return next(err); + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/users/edit-user.js b/src/routes/users/edit-user.js index ae6cb80..f0be2a1 100644 --- a/src/routes/users/edit-user.js +++ b/src/routes/users/edit-user.js @@ -1,160 +1,160 @@ -const moment = require('moment'); - -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { User } = require('../../models/user'); - -const { validateEditUser } = require('./validations'); - -module.exports = async (req, res, next) => { - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at edit-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - if (user.id !== req.user.id && !req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const data = req.body; - - const { errors, isValid } = validateEditUser(data); - if (!isValid) return res.status(400).json(errors); - - if ( - data.avatar && - !data.avatar.includes('default') && - data.avatar !== user.avatar - ) { - let avatar; - try { - avatar = await Photo.findOne({ url: data.avatar }); - } catch (err) { - console.log(`Avatar ${data.avatar} failed to be found at edit-user`); - return next(err); - } - - if (!avatar) { - return res.status(404).json({ avatar: 'Not found' }); - } - - user.avatar = data.avatar; - } else if (data.avatar === '') { - user.avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/users/avatars/default.png`; - } - - user.description = data.description || user.description; - - user.disabilities = data.disabilities || user.disabilities; - - user.firstName = data.firstName - ? cleanSpaces(data.firstName) - : user.firstName; - - user.gender = data.gender || user.gender; - - user.isSubscribed = - typeof data.isSubscribed !== 'undefined' - ? data.isSubscribed - : user.isSubscribed; - - user.language = data.language || user.language; - - user.lastName = data.lastName ? cleanSpaces(data.lastName) : user.lastName; - - user.phone = data.phone || user.phone; - - user.showDisabilities = - typeof data.showDisabilities !== 'undefined' - ? data.showDisabilities - : user.showDisabilities; - - user.showEmail = - typeof data.showEmail !== 'undefined' ? data.showEmail : user.showEmail; - - user.showPhone = - typeof data.showPhone !== 'undefined' ? data.showPhone : user.showPhone; - - if (data.username && data.username !== user.username) { - let repeatedUser; - try { - repeatedUser = await User.findOne({ - username: data.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${data.username} failed to be found at edit-user.` - ); - return next(err); - } - - if (repeatedUser) { - return res.status(400).json({ username: 'Is already taken' }); - } - - user.username = data.username; - } - - user.zip = data.zip ? cleanSpaces(data.zip) : user.zip; - - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `User ${ - user.id - } failed to be updated at edit-user.\nData: ${JSON.stringify( - data, - null, - 2 - )}` - ); - return next(err); - } - - const dataResponse = { - id: user.id, - avatar: user.avatar, - description: user.description, - disabilities: user.disabilities, - firstName: user.firstName, - gender: user.gender, - isSubscribed: user.isSubscribed, - lastName: user.lastName, - phone: user.phone, - showDisabilities: user.showDisabilities, - showEmail: user.showEmail, - showPhone: user.showPhone, - username: user.username, - zip: user.zip - }; - return res.status(200).json(dataResponse); -}; +const moment = require('moment'); + +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { User } = require('../../models/user'); + +const { validateEditUser } = require('./validations'); + +module.exports = async (req, res, next) => { + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User with Id ${userId} failed to be found at edit-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + if (user.id !== req.user.id && !req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const data = req.body; + + const { errors, isValid } = validateEditUser(data); + if (!isValid) return res.status(400).json(errors); + + if ( + data.avatar && + !data.avatar.includes('default') && + data.avatar !== user.avatar + ) { + let avatar; + try { + avatar = await Photo.findOne({ url: data.avatar }); + } catch (err) { + console.log(`Avatar ${data.avatar} failed to be found at edit-user`); + return next(err); + } + + if (!avatar) { + return res.status(404).json({ avatar: 'Not found' }); + } + + user.avatar = data.avatar; + } else if (data.avatar === '') { + user.avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/users/avatars/default.png`; + } + + user.description = data.description || user.description; + + user.disabilities = data.disabilities || user.disabilities; + + user.firstName = data.firstName + ? cleanSpaces(data.firstName) + : user.firstName; + + user.gender = data.gender || user.gender; + + user.isSubscribed = + typeof data.isSubscribed !== 'undefined' + ? data.isSubscribed + : user.isSubscribed; + + user.language = data.language || user.language; + + user.lastName = data.lastName ? cleanSpaces(data.lastName) : user.lastName; + + user.phone = data.phone || user.phone; + + user.showDisabilities = + typeof data.showDisabilities !== 'undefined' + ? data.showDisabilities + : user.showDisabilities; + + user.showEmail = + typeof data.showEmail !== 'undefined' ? data.showEmail : user.showEmail; + + user.showPhone = + typeof data.showPhone !== 'undefined' ? data.showPhone : user.showPhone; + + if (data.username && data.username !== user.username) { + let repeatedUser; + try { + repeatedUser = await User.findOne({ + username: data.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${data.username} failed to be found at edit-user.` + ); + return next(err); + } + + if (repeatedUser) { + return res.status(400).json({ username: 'Is already taken' }); + } + + user.username = data.username; + } + + user.zip = data.zip ? cleanSpaces(data.zip) : user.zip; + + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `User ${ + user.id + } failed to be updated at edit-user.\nData: ${JSON.stringify( + data, + null, + 2 + )}` + ); + return next(err); + } + + const dataResponse = { + id: user.id, + avatar: user.avatar, + description: user.description, + disabilities: user.disabilities, + firstName: user.firstName, + gender: user.gender, + isSubscribed: user.isSubscribed, + lastName: user.lastName, + phone: user.phone, + showDisabilities: user.showDisabilities, + showEmail: user.showEmail, + showPhone: user.showPhone, + username: user.username, + zip: user.zip + }; + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/users/get-profile.js b/src/routes/users/get-profile.js index 0d83096..f9685c0 100644 --- a/src/routes/users/get-profile.js +++ b/src/routes/users/get-profile.js @@ -1,93 +1,93 @@ -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const getUserTeams = req.user.teams.map(t => Team.findOne({ _id: t })); - let userTeams; - try { - userTeams = await Promise.all(getUserTeams); - } catch (err) { - console.log('Teams failed to be found at get-profile'); - return next(err); - } - - const teams = []; - const managedTeams = []; - userTeams.map(t => { - if (t) { - const teamManagers = t.managers.map(m => m.toString()); - if (teamManagers.includes(req.user.id)) { - managedTeams.push({ - id: t.id.toString(), - avatar: t.avatar, - name: t.name - }); - } else { - teams.push({ - id: t.id.toString(), - avatar: t.avatar, - name: t.name - }); - } - } - }); - - const getUserEvents = req.user.events.map(e => Event.findOne({ _id: e })); - let userEvents; - try { - userEvents = await Promise.all(getUserEvents); - } catch (err) { - console.log('Events failed to be found at get-profile'); - return next(err); - } - - const events = []; - const managedEvents = []; - userEvents.map(e => { - if (e) { - const eventManagers = e.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - managedEvents.push({ - id: e.id.toString(), - endDate: e.endDate, - name: e.name, - poster: e.poster, - startDate: e.startDate - }); - } else { - events.push({ - id: e.id.toString(), - endDate: e.endDate, - name: e.name, - poster: e.poster, - startDate: e.startDate - }); - } - } - }); - - const userData = { - id: req.user.id, - avatar: req.user.avatar, - description: req.user.description, - disabilities: req.user.disabilities, - email: req.user.email, - events, - firstName: req.user.firstName, - gender: req.user.gender, - isSubscribed: req.user.isSubscribed, - lastName: req.user.lastName, - managedEvents, - managedTeams, - phone: req.user.phone, - reviewFieldsAmount: req.user.reviewFieldsAmount, - reviewsAmount: req.user.reviewsAmount, - showDisabilities: req.user.showDisabilities, - showEmail: req.user.showEmail, - showPhone: req.user.showPhone, - teams, - username: req.user.username, - zip: req.user.zip - }; - return res.status(200).json(userData); -}; +const { Event } = require('../../models/event'); +const { Team } = require('../../models/team'); + +module.exports = async (req, res, next) => { + const getUserTeams = req.user.teams.map((t) => Team.findOne({ _id: t })); + let userTeams; + try { + userTeams = await Promise.all(getUserTeams); + } catch (err) { + console.log('Teams failed to be found at get-profile'); + return next(err); + } + + const teams = []; + const managedTeams = []; + userTeams.map((t) => { + if (t) { + const teamManagers = t.managers.map((m) => m.toString()); + if (teamManagers.includes(req.user.id)) { + managedTeams.push({ + id: t.id.toString(), + avatar: t.avatar, + name: t.name + }); + } else { + teams.push({ + id: t.id.toString(), + avatar: t.avatar, + name: t.name + }); + } + } + }); + + const getUserEvents = req.user.events.map((e) => Event.findOne({ _id: e })); + let userEvents; + try { + userEvents = await Promise.all(getUserEvents); + } catch (err) { + console.log('Events failed to be found at get-profile'); + return next(err); + } + + const events = []; + const managedEvents = []; + userEvents.map((e) => { + if (e) { + const eventManagers = e.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + managedEvents.push({ + id: e.id.toString(), + endDate: e.endDate, + name: e.name, + poster: e.poster, + startDate: e.startDate + }); + } else { + events.push({ + id: e.id.toString(), + endDate: e.endDate, + name: e.name, + poster: e.poster, + startDate: e.startDate + }); + } + } + }); + + const userData = { + id: req.user.id, + avatar: req.user.avatar, + description: req.user.description, + disabilities: req.user.disabilities, + email: req.user.email, + events, + firstName: req.user.firstName, + gender: req.user.gender, + isSubscribed: req.user.isSubscribed, + lastName: req.user.lastName, + managedEvents, + managedTeams, + phone: req.user.phone, + reviewFieldsAmount: req.user.reviewFieldsAmount, + reviewsAmount: req.user.reviewsAmount, + showDisabilities: req.user.showDisabilities, + showEmail: req.user.showEmail, + showPhone: req.user.showPhone, + teams, + username: req.user.username, + zip: req.user.zip + }; + return res.status(200).json(userData); +}; diff --git a/src/routes/users/get-user.js b/src/routes/users/get-user.js index a24972f..f6d7a08 100644 --- a/src/routes/users/get-user.js +++ b/src/routes/users/get-user.js @@ -1,127 +1,127 @@ -const mongoose = require('mongoose'); - -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - const userId = req.params.userId; - - const userIdObj = mongoose.Types.ObjectId(userId); - let user; - try { - user = await User.aggregate([ - { - $match: { _id: userIdObj } - }, - { - $lookup: { - from: 'events', - let: { events: '$events' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$events'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - endDate: 1, - name: 1, - poster: 1, - startDate: 1 - } - } - ], - as: 'events' - } - }, - { - $lookup: { - from: 'teams', - let: { teams: '$teams' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$teams'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'teams' - } - }, - { - $lookup: { - from: 'users', - let: { reviewsAmount: '$reviewsAmount' }, - pipeline: [ - { - $match: { - $expr: { - $gt: ['$reviewsAmount', '$$reviewsAmount'] - } - } - }, - { - $count: 'ranking' - } - ], - as: 'ranking' - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - description: 1, - disabilities: 1, - email: 1, - events: 1, - firstName: 1, - gender: 1, - isSubscribed: 1, - language: 1, - lastName: 1, - phone: 1, - ranking: 1, - reviewsAmount: 1, - showDisabilities: 1, - showEmail: 1, - showPhone: 1, - teams: 1, - username: 1, - zip: 1 - } - } - ]); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User ${userId} failed to be found at get-user`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - const dataResponse = Object.assign({}, user[0], { - ranking: user[0].ranking.length ? user[0].ranking[0].ranking + 1 : 1 - }); - return res.status(200).json(dataResponse); -}; +const mongoose = require('mongoose'); + +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + const userId = req.params.userId; + + const userIdObj = new mongoose.Types.ObjectId(userId); + let user; + try { + user = await User.aggregate([ + { + $match: { _id: userIdObj } + }, + { + $lookup: { + from: 'events', + let: { events: '$events' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$events'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + endDate: 1, + name: 1, + poster: 1, + startDate: 1 + } + } + ], + as: 'events' + } + }, + { + $lookup: { + from: 'teams', + let: { teams: '$teams' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$teams'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + name: 1 + } + } + ], + as: 'teams' + } + }, + { + $lookup: { + from: 'users', + let: { reviewsAmount: '$reviewsAmount' }, + pipeline: [ + { + $match: { + $expr: { + $gt: ['$reviewsAmount', '$$reviewsAmount'] + } + } + }, + { + $count: 'ranking' + } + ], + as: 'ranking' + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + description: 1, + disabilities: 1, + email: 1, + events: 1, + firstName: 1, + gender: 1, + isSubscribed: 1, + language: 1, + lastName: 1, + phone: 1, + ranking: 1, + reviewsAmount: 1, + showDisabilities: 1, + showEmail: 1, + showPhone: 1, + teams: 1, + username: 1, + zip: 1 + } + } + ]); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User ${userId} failed to be found at get-user`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + const dataResponse = Object.assign({}, user[0], { + ranking: user[0].ranking.length ? user[0].ranking[0].ranking + 1 : 1 + }); + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/users/index.js b/src/routes/users/index.js index ec792de..eb38e7a 100644 --- a/src/routes/users/index.js +++ b/src/routes/users/index.js @@ -1,43 +1,43 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const archiveUser = require('./archive-user'); -const blockUser = require('./block-user'); -const changePassword = require('./change-password'); -const createUser = require('./create-user'); -const deleteUser = require('./delete-user'); -const editUser = require('./edit-user'); -const getUser = require('./get-user'); -const getProfile = require('./get-profile'); -const listUsers = require('./list-users'); -const unblockUser = require('./unblock-user'); -const deactivateUser = require('./deactivate-user'); - -const router = new express.Router(); - -router.get('/profile', isAuthenticated({ isOptional: false }), getProfile); -router.put('/password', isAuthenticated({ isOptional: false }), changePassword); -router.get('', isAuthenticated({ isOptional: false }), listUsers); -router.post('', isAuthenticated({ isOptional: false }), createUser); -router.get('/:userId', getUser); -router.put('/:userId', isAuthenticated({ isOptional: false }), editUser); -router.delete( - '/deactivate', - isAuthenticated({ isOptional: false }), - deactivateUser -); -router.delete('/:userId', isAuthenticated({ isOptional: false }), deleteUser); -router.put( - '/:userId/archive', - isAuthenticated({ isOptional: false }), - archiveUser -); -router.put('/:userId/block', isAuthenticated({ isOptional: false }), blockUser); -router.put( - '/:userId/unblock', - isAuthenticated({ isOptional: false }), - unblockUser -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const archiveUser = require('./archive-user'); +const blockUser = require('./block-user'); +const changePassword = require('./change-password'); +const createUser = require('./create-user'); +const deleteUser = require('./delete-user'); +const editUser = require('./edit-user'); +const getUser = require('./get-user'); +const getProfile = require('./get-profile'); +const listUsers = require('./list-users'); +const unblockUser = require('./unblock-user'); +const deactivateUser = require('./deactivate-user'); + +const router = new express.Router(); + +router.get('/profile', isAuthenticated({ isOptional: false }), getProfile); +router.put('/password', isAuthenticated({ isOptional: false }), changePassword); +router.get('', isAuthenticated({ isOptional: false }), listUsers); +router.post('', isAuthenticated({ isOptional: false }), createUser); +router.get('/:userId', getUser); +router.put('/:userId', isAuthenticated({ isOptional: false }), editUser); +router.delete( + '/deactivate', + isAuthenticated({ isOptional: false }), + deactivateUser +); +router.delete('/:userId', isAuthenticated({ isOptional: false }), deleteUser); +router.put( + '/:userId/archive', + isAuthenticated({ isOptional: false }), + archiveUser +); +router.put('/:userId/block', isAuthenticated({ isOptional: false }), blockUser); +router.put( + '/:userId/unblock', + isAuthenticated({ isOptional: false }), + unblockUser +); + +module.exports = router; diff --git a/src/routes/users/list-users.js b/src/routes/users/list-users.js index 543cd98..a3d7e7b 100644 --- a/src/routes/users/list-users.js +++ b/src/routes/users/list-users.js @@ -1,75 +1,75 @@ -const { User } = require('../../models/user'); - -const { validateListUsers } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateListUsers(req.query); - if (!isValid) return res.status(400).json(errors); - - const queryParams = req.query; - - const usersQuery = { isArchived: false }; - usersQuery.$text = { $search: queryParams.keywords || '' }; - - const sort = queryParams.sortBy || { - score: { $meta: 'textScore' } - }; - let page = queryParams.page ? parseInt(queryParams.page, 10) - 1 : 1; - const pageLimit = queryParams.pageLimit - ? parseInt(queryParams.pageLimit, 10) - : 12; - - let total; - let users; - try { - [users, total] = await Promise.all([ - User.aggregate() - .match(usersQuery) - .project({ - _id: 0, - id: '$_id', - avatar: 1, - email: 1, - firstName: 1, - lastName: 1, - score: { $meta: 'textScore' }, - username: 1 - }) - .match({ score: { $gt: 1 } }) - .sort(sort) - .skip(page * pageLimit) - .limit(pageLimit), - User.find(usersQuery).count() - ]); - } catch (err) { - console.log( - `Users failed to be found or count at list-users.\nusersQuery: ${JSON.stringify( - usersQuery - )}` - ); - return next(err); - } - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - page += 1; - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be less than or equal to ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - const dataResponse = { - page, - lastPage, - pageLimit, - total, - sortBy: queryParams.sortBy, - results: users - }; - return res.status(200).json(dataResponse); -}; +const { User } = require('../../models/user'); + +const { validateListUsers } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateListUsers(req.query); + if (!isValid) return res.status(400).json(errors); + + const queryParams = req.query; + + const usersQuery = { isArchived: false }; + usersQuery.$text = { $search: queryParams.keywords || '' }; + + const sort = queryParams.sortBy || { + score: { $meta: 'textScore' } + }; + let page = queryParams.page ? parseInt(queryParams.page, 10) - 1 : 1; + const pageLimit = queryParams.pageLimit + ? parseInt(queryParams.pageLimit, 10) + : 12; + + let total; + let users; + try { + [users, total] = await Promise.all([ + User.aggregate() + .match(usersQuery) + .project({ + _id: 0, + id: '$_id', + avatar: 1, + email: 1, + firstName: 1, + lastName: 1, + score: { $meta: 'textScore' }, + username: 1 + }) + .match({ score: { $gt: 1 } }) + .sort(sort) + .skip(page * pageLimit) + .limit(pageLimit), + User.find(usersQuery).count() + ]); + } catch (err) { + console.log( + `Users failed to be found or count at list-users.\nusersQuery: ${JSON.stringify( + usersQuery + )}` + ); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + page += 1; + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be less than or equal to ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + + const dataResponse = { + page, + lastPage, + pageLimit, + total, + sortBy: queryParams.sortBy, + results: users + }; + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/users/unblock-user.js b/src/routes/users/unblock-user.js index 88a9c17..3340936 100644 --- a/src/routes/users/unblock-user.js +++ b/src/routes/users/unblock-user.js @@ -1,41 +1,41 @@ -const moment = require('moment'); - -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at unblock-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - user.isBlocked = false; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User with Id ${user.id} failed to be updated at unblock-user.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User with Id ${userId} failed to be found at unblock-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + user.isBlocked = false; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User with Id ${user.id} failed to be updated at unblock-user.` + ); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/users/validations.js b/src/routes/users/validations.js index 66236ae..d59b5f9 100644 --- a/src/routes/users/validations.js +++ b/src/routes/users/validations.js @@ -1,299 +1,299 @@ -const freemail = require('freemail'); -const { isEmail, isInt } = require('validator'); -const { isEmpty } = require('lodash'); -const slugify = require('speakingurl'); - -const { cleanSpaces } = require('../../helpers'); -const { User } = require('../../models/user'); - -module.exports = { - validateChangePassword(data) { - const errors = {}; - - if (!data.oldPassword) { - errors.oldPassword = 'Is required'; - } else if (typeof data.oldPassword !== 'string') { - errors.oldPassword = 'Should be a string'; - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should have more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should have less than 31 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateCreateUser(data) { - const errors = {}; - - if (data.description) { - if (typeof data.description !== 'string') { - errors.description = 'Should be a string'; - } else if (cleanSpaces(data.description).length > 2000) { - errors.description = 'Should have less than 2001 characters'; - } - } - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (cleanSpaces(data.email).length > 254) { - errors.email = 'Should have less than 255 characters'; - } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { - errors.email = 'Is not a valid email'; - } - - if (!data.firstName) { - errors.firstName = 'Is required'; - } else if (typeof data.firstName !== 'string') { - errors.firstName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { - errors.firstName = 'Should only have letters'; - } else if (cleanSpaces(data.firstName).length > 24) { - errors.firstName = 'Should have less than 25 characters'; - } else { - const firstName = cleanSpaces(data.firstName); - - if (firstName.split(' ').length > 1) { - errors.firstName = 'Should only be one name'; - } - } - - if (!data.lastName) { - errors.lastName = 'Is required'; - } else if (typeof data.lastName !== 'string') { - errors.lastName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { - errors.lastName = 'Should only have letters'; - } else if (cleanSpaces(data.lastName).length > 36) { - errors.lastName = 'Should have less than 37 characters'; - } else { - const lastName = cleanSpaces(data.lastName); - - if (lastName.split(' ').length > 1) { - errors.lastName = 'Should only be one last name'; - } - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should be more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should be less than 31 characters'; - } - - if (data.phone) { - if (typeof data.phone !== 'string') { - errors.phone = 'Should be a string'; - } else if (cleanSpaces(data.phone).length > 50) { - errors.phone = 'Should have less than 51 characters'; - } - } - - if (data.username) { - if (typeof data.username !== 'string') { - errors.username = 'Should be a string'; - } else if (cleanSpaces(data.username).length > 67) { - errors.username = 'Should have less than 68 characters'; - } else { - const username = slugify(data.username); - - if (username !== data.username) { - errors.username = 'Should only have lowercase letters and hyphens'; - } - } - } - - if (data.zip) { - if (typeof data.zip !== 'string') { - errors.zip = 'Should be a string'; - } else if (cleanSpaces(data.zip).length > 32) { - errors.zip = 'Should have less than 33 characters'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditUser(data) { - const errors = {}; - - if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { - errors.avatar = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (typeof data.disabilities !== 'undefined') { - if (!Array.isArray(data.disabilities)) { - errors.disabilities = 'Should be an array'; - } else { - const disabilitiesTypes = [ - 'brain', - 'cognitive', - 'hearing', - 'invisible', - 'none', - 'other', - 'physical', - 'private', - 'psychological', - 'spinal-cord', - 'vision' - ]; - data.disabilities.some(d => { - if (typeof d !== 'string') { - errors.disabilities = 'All values should be strings'; - return true; - } else if (!disabilitiesTypes.includes(d)) { - errors.disabilities = 'All values should be valid disabilities'; - return true; - } - }); - } - } - - if (typeof data.firstName !== 'undefined') { - if (typeof data.firstName !== 'string') { - errors.firstName = 'Should be a string'; - } else if (data.firstName === '') { - errors.firstName = 'Is required'; - } else if ( - /[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName) - ) { - errors.firstName = 'Should only have letters'; - } else { - const firstName = cleanSpaces(data.firstName); - - if (firstName.split(' ').length > 1) { - errors.firstName = 'Should only be one first name'; - } - } - } - - if (typeof data.gender !== 'undefined') { - const gendersTypes = User.schema.path('gender').enumValues; - if (typeof data.gender !== 'string') { - errors.gender = 'Should be a string'; - } else if (data.gender === '') { - errors.gender = 'Is required'; - } else if (!gendersTypes.includes(data.gender)) { - errors.gender = 'Should be a valid gender'; - } - } - - if ( - typeof data.isSubscribed !== 'undefined' && - typeof data.isSubscribed !== 'boolean' - ) { - errors.isSubscribed = 'Should be a boolean'; - } - - if (typeof data.lastName !== 'undefined') { - if (typeof data.lastName !== 'string') { - errors.lastName = 'Should be a string'; - } else if (data.lastName === '') { - errors.lastName = 'Is required'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { - errors.lastName = 'Should only have letters'; - } else { - const lastName = cleanSpaces(data.lastName); - - if (lastName.split(' ').length > 1) { - errors.lastName = 'Should only be one last name'; - } - } - } - - if (typeof data.phone !== 'undefined' && typeof data.phone !== 'string') { - errors.phone = 'Should be a string'; - } - - if ( - typeof data.showDisabilities !== 'undefined' && - typeof data.showDisabilities !== 'boolean' - ) { - errors.showDisabilities = 'Should be a boolean'; - } - - if ( - typeof data.showEmail !== 'undefined' && - typeof data.showEmail !== 'boolean' - ) { - errors.showEmail = 'Should be a boolean'; - } - - if ( - typeof data.showPhone !== 'undefined' && - typeof data.showPhone !== 'boolean' - ) { - errors.showPhone = 'Should be a boolean'; - } - - if (typeof data.username !== 'undefined') { - if (typeof data.username !== 'string') { - errors.username = 'Should be a string'; - } else if (data.username === '') { - errors.username = 'Is required'; - } else { - const username = slugify(data.username); - - if (username !== data.username) { - errors.username = 'Should only have lowercase letters and hyphens'; - } - } - } - - if (typeof data.zip !== 'undefined' && typeof data.zip !== 'string') { - errors.zip = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListUsers(queryParams) { - const errors = {}; - - if (queryParams.page && !isInt(queryParams.page)) { - errors.page = 'Should be a integer'; - } else if (parseInt(queryParams.page, 10) < 1) { - errors.page = 'Should be greater than or equal to 1'; - } - - if (queryParams.pageLimit && !isInt(queryParams.pageLimit)) { - errors.pageLimit = 'Should be a integer'; - } else if (parseInt(queryParams.pageLimit, 10) < 1) { - errors.pageLimit = 'Should be greater than or equal to 1'; - } else if (parseInt(queryParams.pageLimit, 10) > 12) { - errors.pageLimit = 'Should be less than or equal to 12'; - } - - const sortOptions = [ - 'email', - '-email', - 'firstName', - '-firstName', - 'lastName', - '-lastName', - 'username', - '-username' - ]; - if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { - errors.sortBy = 'Should be a valid sort'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const freemail = require('freemail'); +const { isEmail, isInt } = require('validator'); +const { isEmpty } = require('lodash'); +const slugify = require('speakingurl'); + +const { cleanSpaces } = require('../../helpers'); +const { User } = require('../../models/user'); + +module.exports = { + validateChangePassword(data) { + const errors = {}; + + if (!data.oldPassword) { + errors.oldPassword = 'Is required'; + } else if (typeof data.oldPassword !== 'string') { + errors.oldPassword = 'Should be a string'; + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } else if (data.password.length < 8) { + errors.password = 'Should have more than 7 characters'; + } else if (data.password.length > 30) { + errors.password = 'Should have less than 31 characters'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateCreateUser(data) { + const errors = {}; + + if (data.description) { + if (typeof data.description !== 'string') { + errors.description = 'Should be a string'; + } else if (cleanSpaces(data.description).length > 2000) { + errors.description = 'Should have less than 2001 characters'; + } + } + + if (!data.email) { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } else if (cleanSpaces(data.email).length > 254) { + errors.email = 'Should have less than 255 characters'; + } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { + errors.email = 'Is not a valid email'; + } + + if (!data.firstName) { + errors.firstName = 'Is required'; + } else if (typeof data.firstName !== 'string') { + errors.firstName = 'Should be a string'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { + errors.firstName = 'Should only have letters'; + } else if (cleanSpaces(data.firstName).length > 24) { + errors.firstName = 'Should have less than 25 characters'; + } else { + const firstName = cleanSpaces(data.firstName); + + if (firstName.split(' ').length > 1) { + errors.firstName = 'Should only be one name'; + } + } + + if (!data.lastName) { + errors.lastName = 'Is required'; + } else if (typeof data.lastName !== 'string') { + errors.lastName = 'Should be a string'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { + errors.lastName = 'Should only have letters'; + } else if (cleanSpaces(data.lastName).length > 36) { + errors.lastName = 'Should have less than 37 characters'; + } else { + const lastName = cleanSpaces(data.lastName); + + if (lastName.split(' ').length > 1) { + errors.lastName = 'Should only be one last name'; + } + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } else if (data.password.length < 8) { + errors.password = 'Should be more than 7 characters'; + } else if (data.password.length > 30) { + errors.password = 'Should be less than 31 characters'; + } + + if (data.phone) { + if (typeof data.phone !== 'string') { + errors.phone = 'Should be a string'; + } else if (cleanSpaces(data.phone).length > 50) { + errors.phone = 'Should have less than 51 characters'; + } + } + + if (data.username) { + if (typeof data.username !== 'string') { + errors.username = 'Should be a string'; + } else if (cleanSpaces(data.username).length > 67) { + errors.username = 'Should have less than 68 characters'; + } else { + const username = slugify(data.username); + + if (username !== data.username) { + errors.username = 'Should only have lowercase letters and hyphens'; + } + } + } + + if (data.zip) { + if (typeof data.zip !== 'string') { + errors.zip = 'Should be a string'; + } else if (cleanSpaces(data.zip).length > 32) { + errors.zip = 'Should have less than 33 characters'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditUser(data) { + const errors = {}; + + if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { + errors.avatar = 'Should be a string'; + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + if (typeof data.disabilities !== 'undefined') { + if (!Array.isArray(data.disabilities)) { + errors.disabilities = 'Should be an array'; + } else { + const disabilitiesTypes = [ + 'brain', + 'cognitive', + 'hearing', + 'invisible', + 'none', + 'other', + 'physical', + 'private', + 'psychological', + 'spinal-cord', + 'vision' + ]; + data.disabilities.some((d) => { + if (typeof d !== 'string') { + errors.disabilities = 'All values should be strings'; + return true; + } else if (!disabilitiesTypes.includes(d)) { + errors.disabilities = 'All values should be valid disabilities'; + return true; + } + }); + } + } + + if (typeof data.firstName !== 'undefined') { + if (typeof data.firstName !== 'string') { + errors.firstName = 'Should be a string'; + } else if (data.firstName === '') { + errors.firstName = 'Is required'; + } else if ( + /[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName) + ) { + errors.firstName = 'Should only have letters'; + } else { + const firstName = cleanSpaces(data.firstName); + + if (firstName.split(' ').length > 1) { + errors.firstName = 'Should only be one first name'; + } + } + } + + if (typeof data.gender !== 'undefined') { + const gendersTypes = User.schema.path('gender').enumValues; + if (typeof data.gender !== 'string') { + errors.gender = 'Should be a string'; + } else if (data.gender === '') { + errors.gender = 'Is required'; + } else if (!gendersTypes.includes(data.gender)) { + errors.gender = 'Should be a valid gender'; + } + } + + if ( + typeof data.isSubscribed !== 'undefined' && + typeof data.isSubscribed !== 'boolean' + ) { + errors.isSubscribed = 'Should be a boolean'; + } + + if (typeof data.lastName !== 'undefined') { + if (typeof data.lastName !== 'string') { + errors.lastName = 'Should be a string'; + } else if (data.lastName === '') { + errors.lastName = 'Is required'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { + errors.lastName = 'Should only have letters'; + } else { + const lastName = cleanSpaces(data.lastName); + + if (lastName.split(' ').length > 1) { + errors.lastName = 'Should only be one last name'; + } + } + } + + if (typeof data.phone !== 'undefined' && typeof data.phone !== 'string') { + errors.phone = 'Should be a string'; + } + + if ( + typeof data.showDisabilities !== 'undefined' && + typeof data.showDisabilities !== 'boolean' + ) { + errors.showDisabilities = 'Should be a boolean'; + } + + if ( + typeof data.showEmail !== 'undefined' && + typeof data.showEmail !== 'boolean' + ) { + errors.showEmail = 'Should be a boolean'; + } + + if ( + typeof data.showPhone !== 'undefined' && + typeof data.showPhone !== 'boolean' + ) { + errors.showPhone = 'Should be a boolean'; + } + + if (typeof data.username !== 'undefined') { + if (typeof data.username !== 'string') { + errors.username = 'Should be a string'; + } else if (data.username === '') { + errors.username = 'Is required'; + } else { + const username = slugify(data.username); + + if (username !== data.username) { + errors.username = 'Should only have lowercase letters and hyphens'; + } + } + } + + if (typeof data.zip !== 'undefined' && typeof data.zip !== 'string') { + errors.zip = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListUsers(queryParams) { + const errors = {}; + + if (queryParams.page && !isInt(queryParams.page)) { + errors.page = 'Should be a integer'; + } else if (parseInt(queryParams.page, 10) < 1) { + errors.page = 'Should be greater than or equal to 1'; + } + + if (queryParams.pageLimit && !isInt(queryParams.pageLimit)) { + errors.pageLimit = 'Should be a integer'; + } else if (parseInt(queryParams.pageLimit, 10) < 1) { + errors.pageLimit = 'Should be greater than or equal to 1'; + } else if (parseInt(queryParams.pageLimit, 10) > 12) { + errors.pageLimit = 'Should be less than or equal to 12'; + } + + const sortOptions = [ + 'email', + '-email', + 'firstName', + '-firstName', + 'lastName', + '-lastName', + 'username', + '-username' + ]; + if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { + errors.sortBy = 'Should be a valid sort'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/venues/archive-venue.js b/src/routes/venues/archive-venue.js index af8a0c6..bfaf8b9 100644 --- a/src/routes/venues/archive-venue.js +++ b/src/routes/venues/archive-venue.js @@ -1,39 +1,39 @@ -const moment = require('moment'); - -const { Venue } = require('../../models/venue'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const venueId = req.params.venueId; - - let venue; - try { - venue = await Venue.findOne({ _id: venueId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Venue not found' }); - } - - console.log(`Venue ${venueId} failed to be found at delete-venue`); - return next(err); - } - - if (!venue) { - return res.status(404).json({ general: 'Venue not found' }); - } - - venue.isArchived = true; - venue.updatedAt = moment.utc().toDate(); - - try { - await venue.save(); - } catch (err) { - console.log(`Venue ${venue.id} failed to be updated at delete-venue`); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Venue } = require('../../models/venue'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const venueId = req.params.venueId; + + let venue; + try { + venue = await Venue.findOne({ _id: venueId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Venue not found' }); + } + + console.log(`Venue ${venueId} failed to be found at delete-venue`); + return next(err); + } + + if (!venue) { + return res.status(404).json({ general: 'Venue not found' }); + } + + venue.isArchived = true; + venue.updatedAt = moment.utc().toDate(); + + try { + await venue.save(); + } catch (err) { + console.log(`Venue ${venue.id} failed to be updated at delete-venue`); + return next(err); + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/venues/get-venue.js b/src/routes/venues/get-venue.js index d1b3fe8..bc30464 100644 --- a/src/routes/venues/get-venue.js +++ b/src/routes/venues/get-venue.js @@ -1,347 +1,348 @@ -const axios = require('axios'); -const { isEqual } = require('lodash'); -const slugify = require('speakingurl'); - -const { Venue } = require('../../models/venue'); -const venueReviewSummary = require('../../helpers/venue-review-summary.js'); - -module.exports = async (req, res, next) => { - const placeId = req.params.placeId; - - let response; - try { - response = await axios.get( - `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ - process.env.PLACES_API_KEY - }` - ); - } catch (err) { - console.log(`Place ${placeId} failed to be found at get-venue.`); - return next(err); - } - - const statusResponse = response.data.status; - if (statusResponse !== 'OK') { - return res.status(404).json({ general: 'Place not found' }); - } - - const placeData = response.data.result; - const dataResponse = {}; - dataResponse.address = placeData.formatted_address; - - let useStreetviewCover = false; - let streetViewError = false; - let streetViewResponse; - try { - streetViewResponse = await axios.get( - `https://maps.googleapis.com/maps/api/streetview/metadata?location=${slugify( - dataResponse.address - )}&key=${process.env.PLACES_API_KEY}` - ); - } catch (err) { - console.log(`Streetview for ${placeId} failed to be found at get-venue.`); - streetViewError = true; - } - - let streetViewPanoId; - if (!streetViewError) { - const streetViewMetadataStatus = streetViewResponse.data.status; - if (streetViewMetadataStatus == 'OK') { - useStreetviewCover = true; - streetViewPanoId = streetViewResponse.data.pano_id; - } - } - - if (useStreetviewCover) { - dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/streetview?key=${ - process.env.PLACES_API_KEY - }&size=800x400&fov=110&location=${slugify(dataResponse.address)}`; - //}&size=800x400&fov=110&heading=0&pano=${streetViewPanoId}`; - //seems like heading needs to be set when using pano id but not for the address - } else if (placeData.photos && placeData.photos.length > 0) { - dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/place/photo?key=${ - process.env.PLACES_API_KEY - }&maxwidth=500&photoreference=${placeData.photos[0].photo_reference}`; - } - - let coverPhotoLink = - //(useStreetviewCover) ? - `https://www.google.com/maps/@?api=1&map_action=pano&pano=${streetViewPanoId}&viewpoint=${ - placeData.geometry.location.lat - },${placeData.geometry.location.lng}`; - console.log('Cover photo link: ', coverPhotoLink); - - dataResponse.formattedPhone = placeData.formatted_phone_number; - dataResponse.googleRating = placeData.rating; - dataResponse.googleUrl = placeData.url; - dataResponse.internationalPhone = placeData.international_phone_number; - dataResponse.location = { - lat: placeData.geometry.location.lat, - lng: placeData.geometry.location.lng - }; - dataResponse.name = placeData.name; - dataResponse.placeId = placeId; - dataResponse.types = placeData.types; - dataResponse.website = placeData.website; - - dataResponse.allowsGuideDog = { yes: 0, no: 0 }; - //dataResponse.bathroomReviews = 0; - //dataResponse.bathroomScore = null; - //dataResponse.entryReviews = 0; - //dataResponse.entryScore = null; - dataResponse.hasParking = { yes: 0, no: 0 }; - dataResponse.hasSecondEntry = { yes: 0, no: 0 }; - dataResponse.hasWellLit = { yes: 0, no: 0 }; - dataResponse.isQuiet = { yes: 0, no: 0 }; - dataResponse.isSpacious = { yes: 0, no: 0 }; - dataResponse.steps = { - zero: 0, - one: 0, - two: 0, - moreThanTwo: 0 - }; - - //new expanded fields - dataResponse.hasPermanentRamp = { yes: 0, no: 0 }; - dataResponse.hasPortableRamp = { yes: 0, no: 0 }; - dataResponse.hasWideEntrance = { yes: 0, no: 0 }; - dataResponse.hasAccessibleTableHeight = { yes: 0, no: 0 }; - dataResponse.hasAccessibleElevator = { yes: 0, no: 0 }; - dataResponse.hasInteriorRamp = { yes: 0, no: 0 }; - dataResponse.hasSwingOutDoor = { yes: 0, no: 0 }; - dataResponse.hasLargeStall = { yes: 0, no: 0 }; - dataResponse.hasSupportAroundToilet = { yes: 0, no: 0 }; - dataResponse.hasLoweredSinks = { yes: 0, no: 0 }; - - dataResponse.entranceScore = 0; - dataResponse.entranceGlyphs = ''; - dataResponse.interiorScore = 0; - dataResponse.interiorGlyphs = ''; - dataResponse.restroomScore = 0; - dataResponse.restroomGlyphs = ''; - dataResponse.mapMarkerScore = 0; - - let venue; - let venueToSave; - try { - [venue, venueToSave] = await Promise.all([ - Venue.aggregate([ - { - $match: { placeId, isArchived: false } - }, - { - $lookup: { - from: 'reviews', - let: { reviews: '$reviews' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$reviews'] - } - } - }, - { - $lookup: { - from: 'users', - let: { user: '$user' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$user'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'user' - } - }, - { - $project: { - _id: 0, - id: '$_id', - //bathroomScore: 1, - comments: 1, - createdAt: 1, - //entryScore: 1, - user: 1, - voters: 1 - } - } - ], - as: 'reviews' - } - }, - { - $lookup: { - from: 'photos', - let: { photos: { $ifNull: ['$photos', []] } }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$photos'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - url: 1 - } - } - ], - as: 'photos' - } - }, - { - $project: { - _id: 0, - id: '$_id', - address: 1, - description: 1, - allowsGuideDog: 1, - //bathroomReviews: 1, - //bathroomScore: 1, - //entryReviews: 1, - //entryScore: 1, - hasParking: 1, - hasSecondEntry: 1, - hasWellLit: 1, - isQuiet: 1, - isSpacious: 1, - location: 1, - name: 1, - photos: 1, - placeId: 1, - steps: 1, - types: 1, - reviews: 1, - hasPermanentRamp: 1, - hasPortableRamp: 1, - hasWideEntrance: 1, - hasAccessibleTableHeight: 1, - hasAccessibleElevator: 1, - hasInteriorRamp: 1, - hasSwingOutDoor: 1, - hasLargeStall: 1, - hasSupportAroundToilet: 1, - hasLoweredSinks: 1 - } - } - ]), - Venue.findOne({ placeId, isArchived: false }) - ]); - } catch (err) { - console.log( - `Venue with placeId ${placeId} failed to be found at get-venue` - ); - return next(err); - } - - if (venue && venue[0]) { - let venueHasUpdates = false; - if (venueToSave.address !== dataResponse.address) { - venueToSave.address = dataResponse.address; - venueHasUpdates = true; - } - if ( - venueToSave.location.coordinates[0] !== dataResponse.location.lng || - venueToSave.location.coordinates[1] !== dataResponse.location.lat - ) { - venueToSave.location.coordinates = [ - dataResponse.location.lng, - dataResponse.location.lat - ]; - venueHasUpdates = true; - } - if (venueToSave.name !== dataResponse.name) { - venueToSave.name = dataResponse.name; - venueHasUpdates = true; - } - if (!isEqual(venueToSave.types, dataResponse.types)) { - venueToSave.types = dataResponse.types; - venueHasUpdates = true; - } - - if (venueHasUpdates) { - try { - await venueToSave.save(); - } catch (err) { - console.log( - `Venue with id ${venueToSave.id} failed to be updated at get-venue.` - ); - return next(err); - } - } - - //TEMP: - let scoring; - //console.log('venue0: ', venue[0]); - - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue[0]); - console.log('entrance score: ', scoring); - dataResponse.entranceScore = scoring.ratingLevel; - dataResponse.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue[0]); - console.log('interior score: ', scoring); - dataResponse.interiorScore = scoring.ratingLevel; - dataResponse.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue[0]); - console.log('restroom score: ', scoring); - dataResponse.restroomScore = scoring.ratingLevel; - dataResponse.restroomGlyphs = scoring.ratingGlyphs; - - dataResponse.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - dataResponse.entranceScore, - dataResponse.interiorScore, - dataResponse.restroomScore - ); - - dataResponse.id = venue[0]._id; - - dataResponse.allowsGuideDog = venue[0].allowsGuideDog; - //dataResponse.bathroomReviews = venue[0].bathroomReviews; - //dataResponse.bathroomScore = venue[0].bathroomScore; - //dataResponse.entryReviews = venue[0].entryReviews; - //dataResponse.entryScore = venue[0].entryScore; - dataResponse.hasParking = venue[0].hasParking; - dataResponse.hasSecondEntry = venue[0].hasSecondEntry; - dataResponse.hasWellLit = venue[0].hasWellLit; - dataResponse.isQuiet = venue[0].isQuiet; - dataResponse.isSpacious = venue[0].isSpacious; - dataResponse.photos = venue[0].photos; - dataResponse.steps = venue[0].steps; - //new expanded fields - dataResponse.hasPermanentRamp = venue[0].hasPermanentRamp; - dataResponse.hasPortableRamp = venue[0].hasPortableRamp; - dataResponse.hasWideEntrance = venue[0].hasWideEntrance; - dataResponse.hasAccessibleTableHeight = venue[0].hasAccessibleTableHeight; - dataResponse.hasAccessibleElevator = venue[0].hasAccessibleElevator; - dataResponse.hasInteriorRamp = venue[0].hasInteriorRamp; - dataResponse.hasSwingOutDoor = venue[0].hasSwingOutDoor; - dataResponse.hasLargeStall = venue[0].hasLargeStall; - dataResponse.hasSupportAroundToilet = venue[0].hasSupportAroundToilet; - dataResponse.hasLoweredSinks = venue[0].hasLoweredSinks; - - dataResponse.reviews = venue[0].reviews; - } - - return res.status(200).json(dataResponse); -}; +const axios = require('axios'); +const { isEqual } = require('lodash'); +const slugify = require('speakingurl'); + +const { Venue } = require('../../models/venue'); +const venueReviewSummary = require('../../helpers/venue-review-summary.js'); + +module.exports = async (req, res, next) => { + const placeId = req.params.placeId; + + let response; + try { + response = await axios.get( + `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ + process.env.PLACES_API_KEY + }` + ); + } catch (err) { + console.log(`Place ${placeId} failed to be found at get-venue.`); + return next(err); + } + + const statusResponse = response.data.status; + if (statusResponse !== 'OK') { + return res.status(404).json({ general: 'Place not found' }); + } + + const placeData = response.data.result; + const dataResponse = {}; + dataResponse.address = placeData.formatted_address; + + let useStreetviewCover = false; + let streetViewError = false; + let streetViewResponse; + try { + streetViewResponse = await axios.get( + `https://maps.googleapis.com/maps/api/streetview/metadata?location=${slugify( + dataResponse.address + )}&key=${process.env.PLACES_API_KEY}` + ); + } catch (err) { + console.error(err); + console.log(`Streetview for ${placeId} failed to be found at get-venue.`); + streetViewError = true; + } + + let streetViewPanoId; + if (!streetViewError) { + const streetViewMetadataStatus = streetViewResponse.data.status; + if (streetViewMetadataStatus == 'OK') { + useStreetviewCover = true; + streetViewPanoId = streetViewResponse.data.pano_id; + } + } + + if (useStreetviewCover) { + dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/streetview?key=${ + process.env.PLACES_API_KEY + }&size=800x400&fov=110&location=${slugify(dataResponse.address)}`; + //}&size=800x400&fov=110&heading=0&pano=${streetViewPanoId}`; + //seems like heading needs to be set when using pano id but not for the address + } else if (placeData.photos && placeData.photos.length > 0) { + dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/place/photo?key=${ + process.env.PLACES_API_KEY + }&maxwidth=500&photoreference=${placeData.photos[0].photo_reference}`; + } + + let coverPhotoLink = + //(useStreetviewCover) ? + `https://www.google.com/maps/@?api=1&map_action=pano&pano=${streetViewPanoId}&viewpoint=${ + placeData.geometry.location.lat + },${placeData.geometry.location.lng}`; + console.log('Cover photo link: ', coverPhotoLink); + + dataResponse.formattedPhone = placeData.formatted_phone_number; + dataResponse.googleRating = placeData.rating; + dataResponse.googleUrl = placeData.url; + dataResponse.internationalPhone = placeData.international_phone_number; + dataResponse.location = { + lat: placeData.geometry.location.lat, + lng: placeData.geometry.location.lng + }; + dataResponse.name = placeData.name; + dataResponse.placeId = placeId; + dataResponse.types = placeData.types; + dataResponse.website = placeData.website; + + dataResponse.allowsGuideDog = { yes: 0, no: 0 }; + //dataResponse.bathroomReviews = 0; + //dataResponse.bathroomScore = null; + //dataResponse.entryReviews = 0; + //dataResponse.entryScore = null; + dataResponse.hasParking = { yes: 0, no: 0 }; + dataResponse.hasSecondEntry = { yes: 0, no: 0 }; + dataResponse.hasWellLit = { yes: 0, no: 0 }; + dataResponse.isQuiet = { yes: 0, no: 0 }; + dataResponse.isSpacious = { yes: 0, no: 0 }; + dataResponse.steps = { + zero: 0, + one: 0, + two: 0, + moreThanTwo: 0 + }; + + //new expanded fields + dataResponse.hasPermanentRamp = { yes: 0, no: 0 }; + dataResponse.hasPortableRamp = { yes: 0, no: 0 }; + dataResponse.hasWideEntrance = { yes: 0, no: 0 }; + dataResponse.hasAccessibleTableHeight = { yes: 0, no: 0 }; + dataResponse.hasAccessibleElevator = { yes: 0, no: 0 }; + dataResponse.hasInteriorRamp = { yes: 0, no: 0 }; + dataResponse.hasSwingOutDoor = { yes: 0, no: 0 }; + dataResponse.hasLargeStall = { yes: 0, no: 0 }; + dataResponse.hasSupportAroundToilet = { yes: 0, no: 0 }; + dataResponse.hasLoweredSinks = { yes: 0, no: 0 }; + + dataResponse.entranceScore = 0; + dataResponse.entranceGlyphs = ''; + dataResponse.interiorScore = 0; + dataResponse.interiorGlyphs = ''; + dataResponse.restroomScore = 0; + dataResponse.restroomGlyphs = ''; + dataResponse.mapMarkerScore = 0; + + let venue; + let venueToSave; + try { + [venue, venueToSave] = await Promise.all([ + Venue.aggregate([ + { + $match: { placeId, isArchived: false } + }, + { + $lookup: { + from: 'reviews', + let: { reviews: '$reviews' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$reviews'] + } + } + }, + { + $lookup: { + from: 'users', + let: { user: '$user' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$user'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'user' + } + }, + { + $project: { + _id: 0, + id: '$_id', + //bathroomScore: 1, + comments: 1, + createdAt: 1, + //entryScore: 1, + user: 1, + voters: 1 + } + } + ], + as: 'reviews' + } + }, + { + $lookup: { + from: 'photos', + let: { photos: { $ifNull: ['$photos', []] } }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$photos'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + url: 1 + } + } + ], + as: 'photos' + } + }, + { + $project: { + _id: 0, + id: '$_id', + address: 1, + description: 1, + allowsGuideDog: 1, + //bathroomReviews: 1, + //bathroomScore: 1, + //entryReviews: 1, + //entryScore: 1, + hasParking: 1, + hasSecondEntry: 1, + hasWellLit: 1, + isQuiet: 1, + isSpacious: 1, + location: 1, + name: 1, + photos: 1, + placeId: 1, + steps: 1, + types: 1, + reviews: 1, + hasPermanentRamp: 1, + hasPortableRamp: 1, + hasWideEntrance: 1, + hasAccessibleTableHeight: 1, + hasAccessibleElevator: 1, + hasInteriorRamp: 1, + hasSwingOutDoor: 1, + hasLargeStall: 1, + hasSupportAroundToilet: 1, + hasLoweredSinks: 1 + } + } + ]), + Venue.findOne({ placeId, isArchived: false }) + ]); + } catch (err) { + console.log( + `Venue with placeId ${placeId} failed to be found at get-venue` + ); + return next(err); + } + + if (venue && venue[0]) { + let venueHasUpdates = false; + if (venueToSave.address !== dataResponse.address) { + venueToSave.address = dataResponse.address; + venueHasUpdates = true; + } + if ( + venueToSave.location.coordinates[0] !== dataResponse.location.lng || + venueToSave.location.coordinates[1] !== dataResponse.location.lat + ) { + venueToSave.location.coordinates = [ + dataResponse.location.lng, + dataResponse.location.lat + ]; + venueHasUpdates = true; + } + if (venueToSave.name !== dataResponse.name) { + venueToSave.name = dataResponse.name; + venueHasUpdates = true; + } + if (!isEqual(venueToSave.types, dataResponse.types)) { + venueToSave.types = dataResponse.types; + venueHasUpdates = true; + } + + if (venueHasUpdates) { + try { + await venueToSave.save(); + } catch (err) { + console.log( + `Venue with id ${venueToSave.id} failed to be updated at get-venue.` + ); + return next(err); + } + } + + //TEMP: + let scoring; + //console.log('venue0: ', venue[0]); + + //calculate entranceScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('entrance', venue[0]); + console.log('entrance score: ', scoring); + dataResponse.entranceScore = scoring.ratingLevel; + dataResponse.entranceGlyphs = scoring.ratingGlyphs; + + //calculate interiorScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('interior', venue[0]); + console.log('interior score: ', scoring); + dataResponse.interiorScore = scoring.ratingLevel; + dataResponse.interiorGlyphs = scoring.ratingGlyphs; + + //calculate restroomScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('restroom', venue[0]); + console.log('restroom score: ', scoring); + dataResponse.restroomScore = scoring.ratingLevel; + dataResponse.restroomGlyphs = scoring.ratingGlyphs; + + dataResponse.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( + dataResponse.entranceScore, + dataResponse.interiorScore, + dataResponse.restroomScore + ); + + dataResponse.id = venue[0]._id; + + dataResponse.allowsGuideDog = venue[0].allowsGuideDog; + //dataResponse.bathroomReviews = venue[0].bathroomReviews; + //dataResponse.bathroomScore = venue[0].bathroomScore; + //dataResponse.entryReviews = venue[0].entryReviews; + //dataResponse.entryScore = venue[0].entryScore; + dataResponse.hasParking = venue[0].hasParking; + dataResponse.hasSecondEntry = venue[0].hasSecondEntry; + dataResponse.hasWellLit = venue[0].hasWellLit; + dataResponse.isQuiet = venue[0].isQuiet; + dataResponse.isSpacious = venue[0].isSpacious; + dataResponse.photos = venue[0].photos; + dataResponse.steps = venue[0].steps; + //new expanded fields + dataResponse.hasPermanentRamp = venue[0].hasPermanentRamp; + dataResponse.hasPortableRamp = venue[0].hasPortableRamp; + dataResponse.hasWideEntrance = venue[0].hasWideEntrance; + dataResponse.hasAccessibleTableHeight = venue[0].hasAccessibleTableHeight; + dataResponse.hasAccessibleElevator = venue[0].hasAccessibleElevator; + dataResponse.hasInteriorRamp = venue[0].hasInteriorRamp; + dataResponse.hasSwingOutDoor = venue[0].hasSwingOutDoor; + dataResponse.hasLargeStall = venue[0].hasLargeStall; + dataResponse.hasSupportAroundToilet = venue[0].hasSupportAroundToilet; + dataResponse.hasLoweredSinks = venue[0].hasLoweredSinks; + + dataResponse.reviews = venue[0].reviews; + } + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/venues/index.js b/src/routes/venues/index.js index 2f35371..94fec3d 100644 --- a/src/routes/venues/index.js +++ b/src/routes/venues/index.js @@ -1,19 +1,19 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const archiveVenue = require('./archive-venue'); -const getVenue = require('./get-venue'); -const listVenues = require('./list-venues'); - -const router = new express.Router(); - -router.get('', listVenues); -router.get('/:placeId', getVenue); -router.put( - '/:venueId/archive', - isAuthenticated({ isOptional: false }), - archiveVenue -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const archiveVenue = require('./archive-venue'); +const getVenue = require('./get-venue'); +const listVenues = require('./list-venues'); + +const router = new express.Router(); + +router.get('', listVenues); +router.get('/:placeId', getVenue); +router.put( + '/:venueId/archive', + isAuthenticated({ isOptional: false }), + archiveVenue +); + +module.exports = router; diff --git a/src/routes/venues/list-venues.js b/src/routes/venues/list-venues.js index 306ddd9..81b6821 100644 --- a/src/routes/venues/list-venues.js +++ b/src/routes/venues/list-venues.js @@ -1,642 +1,630 @@ -const axios = require('axios'); -const { find, isEmpty } = require('lodash'); -const slugify = require('speakingurl'); - -const { isNumber } = require('../../helpers'); -const { Venue } = require('../../models/venue'); - -const { validateListVenues } = require('./validations'); -const venueReviewSummary = require('../../helpers/venue-review-summary.js'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - - const { errors, isValid } = validateListVenues(queryParams); - if (!isValid) return res.status(400).json(errors); - - let coordinates = queryParams.location.split(','); - - //Legacy function from two-bar search, geocodes from string address - if (queryParams.address && !queryParams.page) { - console.log('in address conditional, ', queryParams); - queryParams.name = queryParams.address; - const geocodeParams = `?key=${process.env.PLACES_API_KEY}&address=${slugify( - queryParams.address - )}`; - - let geocodeResponse; - try { - geocodeResponse = await axios.get( - `https://maps.googleapis.com/maps/api/geocode/json${geocodeParams}` - ); - } catch (err) { - console.log( - `Geocode failed to be found at list-venues.\nQuery Params: ${JSON.stringify( - queryParams - )}` - ); - return next(err); - } - - const statusCode = geocodeResponse.data.status; - if (statusCode === 'ZERO_RESULTS') { - return res.status(404).json({ keywords: 'Address not found' }); - } else if (statusCode === 'OVER_QUERY_LIMIT') { - return next(new Error('Over query limit with Google Places API')); - } else if (statusCode === 'REQUEST_DENIED') { - return next(new Error('Request denied with Google Places API')); - } else if (statusCode === 'INVALID_REQUEST') { - return next(new Error('Invalid request with Google Places API')); - } else if (statusCode === 'UNKNOWN_ERROR') { - return next(new Error('Unknown error with Google Places API')); - } - - coordinates = [ - geocodeResponse.data.results[0].geometry.location.lat, - geocodeResponse.data.results[0].geometry.location.lng - ]; - } //end address geocode - - let venuesFilters = {}; - let dbVenuesFilters = {}; - - /* - * Legacy filter string building function, - * has a critical defect condition where if - * no > yes but yes is at least 1, then there - * would be a false match. - */ - if (queryParams.entranceScore) { - venuesFilters.entranceScore = parseFloat(queryParams.entranceScore); - //{ $gte: parseFloat(queryParams.entranceScore) }; - } - - if (queryParams.interiorScore) { - venuesFilters.interiorScore = parseFloat(queryParams.interiorScore); - //{ $gte: parseFloat(queryParams.interiorScore) }; - } - - if (queryParams.restroomScore) { - venuesFilters.restroomScore = parseFloat(queryParams.restroomScore); - //{ $gte: parseFloat(queryParams.restroomScore) }; - } - - if (queryParams.allowsGuideDog) { - venuesFilters.allowsGuideDog = parseFloat(queryParams.allowsGuideDog); - - const allowsGuideDog = parseFloat(queryParams.allowsGuideDog) === 1; - if (allowsGuideDog) { - dbVenuesFilters['allowsGuideDog.yes'] = { $gte: 1 }; - } else { - dbVenuesFilters['allowsGuideDog.no'] = { $gte: 1 }; - } - } - - if (queryParams.hasParking) { - venuesFilters.hasParking = queryParams.hasParking; - - const hasParking = parseFloat(queryParams.hasParking) === 1; - if (hasParking) { - dbVenuesFilters['hasParking.yes'] = { $gte: 1 }; - } else { - dbVenuesFilters['hasParking.no'] = { $gte: 1 }; - } - } - - /* - * Not used - * - if (queryParams.hasRamp) { - const hasRamp = parseFloat(queryParams.hasRamp) === 1; - if (hasRamp) { - venuesFilters['hasRamp.yes'] = { $gte: 1 }; - } else { - venuesFilters['hasRamp.no'] = { $gte: 1 }; - } - } - - if (queryParams.hasSecondEntry) { - const hasSecondEntry = parseFloat(queryParams.hasSecondEntry) === 1; - if (hasSecondEntry) { - venuesFilters['hasSecondEntry.yes'] = { $gte: 1 }; - } else { - venuesFilters['hasSecondEntry.no'] = { $gte: 1 }; - } - } - - if (queryParams.hasWellLit) { - const hasWellLit = parseFloat(queryParams.hasWellLit) === 1; - if (hasWellLit) { - venuesFilters['hasWellLit.yes'] = { $gte: 1 }; - } else { - venuesFilters['hasWellLit.no'] = { $gte: 1 }; - } - } - - if (queryParams.isQuiet) { - const isQuiet = parseFloat(queryParams.isQuiet) === 1; - if (isQuiet) { - venuesFilters['isQuiet.yes'] = { $gte: 1 }; - } else { - venuesFilters['isQuiet.no'] = { $gte: 1 }; - } - } - - if (queryParams.isSpacious) { - const isSpacious = parseFloat(queryParams.isSpacious) === 1; - if (isSpacious) { - venuesFilters['isSpacious.yes'] = { $gte: 1 }; - } else { - venuesFilters['isSpacious.no'] = { $gte: 1 }; - } - } - - if (queryParams.steps) { - if (parseFloat(queryParams.steps) === 0) { - venuesFilters['steps.zero'] = { $gte: 1 }; - } else if (parseFloat(queryParams.steps) === 1) { - venuesFilters['steps.one'] = { $gte: 1 }; - } else if (parseFloat(queryParams.steps) === 2) { - venuesFilters['steps.two'] = { $gte: 1 }; - } else if (parseFloat(queryParams.steps) === 3) { - venuesFilters['steps.moreThanTwo'] = { $gte: 1 }; - } - } - * - */ - - let dataResponse; - - /* - * Legacy filtering function that searches solely on - * AXS Venue data and provides it's own pagination of 20 - * UPDATED 05/2020 TO SUPPORT FILTER ONLY SELF SEARCH - */ - if (!isEmpty(venuesFilters) && isEmpty(queryParams.name)) { - console.log('>> Performing DB search'); - /* - if (queryParams.name) { - //performs literal name match against AXS Venue name - venuesFilters.name = { $regex: queryParams.name, $options: 'i' }; - } - */ - - dbVenuesFilters.location = { - $near: { - $geometry: { - type: 'Point', - coordinates: [coordinates[1], coordinates[0]] - }, - $maxDistance: 50000 - } - }; - - if (queryParams.type) { - dbVenuesFilters.types = queryParams.type; - } - - dbVenuesFilters.isArchived = false; - - let page = 1; - if (isNumber(queryParams.page)) { - page = queryParams.page; - } - - const pageLimit = - venuesFilters.hasOwnProperty('entranceScore') || - venuesFilters.hasOwnProperty('interiorScore') || - venuesFilters.hasOwnProperty('restroomScore') - ? 80 - : 20; - - if (page > 0) { - page -= 1; - } else { - return res - .status(400) - .json({ page: 'Should be equal to or greater than 1' }); - } - - let total; - let venues; - try { - [venues, total] = await Promise.all([ - Venue.find( - dbVenuesFilters - /*,'address allowsGuideDog hasParking hasSecondEntry hasWellLit isQuiet isSpacious location name photos placeId steps types'*/ - ) - .skip(page * pageLimit) - .limit(pageLimit), - Venue.find(dbVenuesFilters).count() - /*TODO: count is deprecated in favor of countDocuments, but that does not support $near - would need to move to GeoWithin but that does not return sorted results - */ - ]); - } catch (err) { - console.log( - `Venues failed to be found or count at list-venues.\nvenuesQuery: ${JSON.stringify( - dbVenuesFilters - )}` - ); - console.log(err); - return next(err); - } - - venues = venues.map(venue => - Object.assign({}, venue.toObject(), { - id: venue._id, - _id: undefined, - location: venue.coordinates - }) - ); - - //+ADDED - //Perform ratings logic on all returned venues - console.log('Raw venues count: ' + venues.length); - venues = venues.filter(venue => { - //console.log('In scoring assignment'); - let scoring; - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); - venue.entranceScore = scoring.ratingLevel; - venue.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue); - venue.interiorScore = scoring.ratingLevel; - venue.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); - venue.restroomScore = scoring.ratingLevel; - venue.restroomGlyphs = scoring.ratingGlyphs; - - venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - venue.entranceScore, - venue.interiorScore, - venue.restroomScore - ); - - let passesValidation = true; - if (venuesFilters.hasOwnProperty('entranceScore')) { - if ( - !venue.entranceScore || - venue.entranceScore < venuesFilters.entranceScore - ) { - passesValidation = false; - } - } - - if (passesValidation && venuesFilters.hasOwnProperty('interiorScore')) { - if ( - !venue.interiorScore || - venue.interiorScore < venuesFilters.interiorScore - ) { - passesValidation = false; - } - } - - if (passesValidation && venuesFilters.hasOwnProperty('restroomScore')) { - if ( - !venue.restroomScore || - venue.restroomScore < venuesFilters.restroomScore - ) { - passesValidation = false; - } - } - - if (passesValidation) { - return venue; - } - }); - - const lastPage = Math.ceil(total / pageLimit); - let nextPage; - if (lastPage > 0) { - page += 1; - if (page > lastPage || page > 3) { - return res.status(400).json({ - page: `Should be equal to or less than ${lastPage > 3 ? 3 : lastPage}` - }); - } - } - - dataResponse = { - nextPage, - results: venues - }; - /* - * End legacy filter - */ - } else { - console.log('>> Performing Google search'); - - /* - * Perform Google search when there text entered or no filters selected - */ - let nearbyParams = `?key=${process.env.PLACES_API_KEY}`; - let searchType = queryParams.name ? 'textsearch' : 'nearbysearch'; - - if (!queryParams.page) { - nearbyParams = `${nearbyParams}&location=${coordinates[0]},${ - coordinates[1] - //}&rankby=distance`; - }`; - - if (queryParams.name) { - //nearbyParams = `${nearbyParams}&keyword=${queryParams.name}`; - nearbyParams = `${nearbyParams}&query=${queryParams.name}&radius=5000`; - } else { - //empty search, such as on load - nearbyParams = `${nearbyParams}&rankby=distance`; - } - - if (queryParams.type) { - nearbyParams = `${nearbyParams}&type=${queryParams.type}`; - } else { - nearbyParams = `${nearbyParams}&type=establishment`; - } - } else { - nearbyParams = `${nearbyParams}&pagetoken=${queryParams.page}`; - } - - if (queryParams.rankby) { - nearbyParams = `${nearbyParams}&rankby=${queryParams.rankby}`; - } - if (queryParams.opennow) { - nearbyParams = `${nearbyParams}&opennow=${queryParams.opennow}`; - } - if (queryParams.minprice) { - nearbyParams = `${nearbyParams}&minprice=${queryParams.minprice}`; - } - if (queryParams.maxprice) { - nearbyParams = `${nearbyParams}&maxprice=${queryParams.maxprice}`; - } - - let placesResponse; - try { - console.log( - 'performing google search: ' + - `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}` - ); - placesResponse = await axios.get( - `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}` - ); - } catch (err) { - console.log( - `Places failed to be found at list-venues.\nQuery Params: ${JSON.stringify( - queryParams - )}` - ); - return next(err); - } - - const statusCode = placesResponse.data.status; - if (statusCode === 'OVER_QUERY_LIMIT') { - return next(new Error('Over query limit with Google Places API')); - } else if (statusCode === 'REQUEST_DENIED') { - return next(new Error('Request denied with Google Places API')); - } else if (statusCode === 'INVALID_REQUEST') { - return next(new Error('Invalid request with Google Places API')); - } else if (statusCode === 'UNKNOWN_ERROR') { - return next(new Error('Unknown error with Google Places API')); - } - //do we need to check for 0? - - if (placesResponse.data.results.length == 1) { - if (placesResponse.data.results[0].types[0] == 'locality') { - console.log( - 'Found a city only: ', - placesResponse.data.results[0].geometry.location - ); - //TODO: redo search with new coordinates and no query/name or change/add "places in " to the first part of the string - } - } - - //Format Google Places results and get array of IDs - let places = []; - const placesIds = []; - placesResponse.data.results.forEach(place => { - let photo = ''; - if (place.photos) { - photo = `https://maps.googleapis.com/maps/api/place/photo?key=${ - process.env.PLACES_API_KEY - }&maxwidth=300&photoreference=${place.photos[0].photo_reference}`; - } - - places.push({ - //address: place.vicinity, - address: place.formatted_address, - location: { - lat: place.geometry.location.lat, - lng: place.geometry.location.lng - }, - name: place.name, - photo, - placeId: place.place_id, - types: place.types - }); - placesIds.push(place.place_id); - }); - - //Use array of Google Place IDs to find AXS Venues - let venues; - try { - venues = await Venue.find({ placeId: { $in: placesIds } }); - } catch (err) { - console.log( - `Venues failed to be found at list-venues.\nPlaces ids: [${placesIds}]` - ); - return next(err); - } - - //Perform ratings logic on all returned venues - venues.forEach(venue => { - //console.log('In scoring assignment'); - let scoring; - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); - venue.entranceScore = scoring.ratingLevel; - venue.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue); - venue.interiorScore = scoring.ratingLevel; - venue.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); - venue.restroomScore = scoring.ratingLevel; - venue.restroomGlyphs = scoring.ratingGlyphs; - - venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - venue.entranceScore, - venue.interiorScore, - venue.restroomScore - ); - }); - - //Filter out, remove, Google Places that are not AXS Venues - // Can't use hasOwnProperty() on mongoose model objects // - if (!isEmpty(venuesFilters)) { - console.log('>> Performing secondary DB filtering'); - places = places.filter(place => { - const venue = find(venues, venue => venue.placeId === place.placeId); - if (venue) { - //console.log('In verification of filters'); - let passesValidation = true; - if ( - passesValidation && - venuesFilters.hasOwnProperty('allowsGuideDog') - ) { - if ( - !venue.allowsGuideDog || - venue.allowsGuideDog.yes < venue.allowsGuideDog.no || - venue.allowsGuideDog.yes == 0 - ) { - passesValidation = false; - } - } - - if (passesValidation && venuesFilters.hasOwnProperty('hasParking')) { - if ( - !venue.hasParking || - venue.hasParking.yes < venue.hasParking.no || - venue.hasParking.yes == 0 - ) { - passesValidation = false; - } - } - - if ( - passesValidation && - venuesFilters.hasOwnProperty('entranceScore') - ) { - if ( - !venue.entranceScore || - venue.entranceScore < venuesFilters.entranceScore - ) { - passesValidation = false; - } - } - - if ( - passesValidation && - venuesFilters.hasOwnProperty('interiorScore') - ) { - if ( - !venue.interiorScore || - venue.interiorScore < venuesFilters.interiorScore - ) { - passesValidation = false; - } - } - - if ( - passesValidation && - venuesFilters.hasOwnProperty('restroomScore') - ) { - if ( - !venue.restroomScore || - venue.restroomScore < venuesFilters.restroomScore - ) { - passesValidation = false; - } - } - - if (passesValidation) { - return venue; - } - } - }); - } //end filtering Google results - - // - places = places.map(place => { - const venue = find(venues, venue => venue.placeId === place.placeId); - if (venue) { - return Object.assign({}, place, { - //new expanded fields - hasPermanentRamp: venue.hasPermanentRamp, - hasPortableRamp: venue.hasPortableRamp, - hasWideEntrance: venue.hasWideEntrance, - hasAccessibleTableHeight: venue.hasAccessibleTableHeight, - hasAccessibleElevator: venue.hasAccessibleElevator, - hasInteriorRamp: venue.hasInteriorRamp, - hasSwingInDoor: venue.hasSwingInDoor, - hasSwingOutDoor: venue.hasSwingOutDoor, - hasLargeStall: venue.hasLargeStall, - hasSupportAroundToilet: venue.hasSupportAroundToilet, - hasLoweredSinks: venue.hasLoweredSinks, - - entranceScore: venue.entranceScore, - entranceGlyphs: venue.entranceGlyphs, - interiorScore: venue.interiorScore, - interiorGlyphs: venue.interiorGlyphs, - restroomScore: venue.restroomScore, - restroomGlyphs: venue.restroomGlyphs, - mapMarkerScore: venue.mapMarkerScore, - - //original fields - allowsGuideDog: venue.allowsGuideDog, - //_bathroomScore: venue.bathroomScore, - //_entryScore: venue.entryScore, - hasParking: venue.hasParking, - hasSecondEntry: venue.hasSecondEntry, - hasWellLit: venue.hasWellLit, - isQuiet: venue.isQuiet, - isSpacious: venue.isSpacious, - steps: venue.steps - }); - } - - //venue not found - return Object.assign({}, place, { - //new expanded fields - hasPermanentRamp: { yes: 0, no: 0 }, - hasPortableRamp: { yes: 0, no: 0 }, - hasWideEntrance: { yes: 0, no: 0 }, - hasAccessibleTableHeight: { yes: 0, no: 0 }, - hasAccessibleElevator: { yes: 0, no: 0 }, - hasInteriorRamp: { yes: 0, no: 0 }, - hasSwingInDoor: { yes: 0, no: 0 }, - hasSwingOutDoor: { yes: 0, no: 0 }, - hasLargeStall: { yes: 0, no: 0 }, - hasSupportAroundToilet: { yes: 0, no: 0 }, - hasLoweredSinks: { yes: 0, no: 0 }, - interiorScore: 0, - interiorGlyphs: 'interior', - restroomScore: 0, - restroomGlyphs: 'restroom', - entranceScore: 0, - entranceGlyphs: 'entrylg', - mapMarkerScore: 0, - - //original fields - allowsGuideDog: { yes: 0, no: 0 }, - //_bathroomReviews: 0, - //_bathroomScore: null, - //_entryReviews: 0, - //_entryScore: null, - hasParking: { yes: 0, no: 0 }, - hasSecondEntry: { yes: 0, no: 0 }, - hasWellLit: { yes: 0, no: 0 }, - isQuiet: { yes: 0, no: 0 }, - isSpacious: { yes: 0, no: 0 }, - steps: { - zero: 0, - one: 0, - two: 0, - moreThanTwo: 0 - } - }); - }); - - dataResponse = { - nextPage: placesResponse.data.next_page_token, - results: places - }; - } //ends legacy filter logic, false conditional - - return res.status(200).json(dataResponse); -}; +const axios = require('axios'); +const { find, isEmpty } = require('lodash'); +const slugify = require('speakingurl'); + +const { isNumber } = require('../../helpers'); +const { Venue } = require('../../models/venue'); + +const { validateListVenues } = require('./validations'); +const venueReviewSummary = require('../../helpers/venue-review-summary.js'); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListVenues(queryParams); + if (!isValid) return res.status(400).json(errors); + + let coordinates = queryParams.location.split(','); + + //Legacy function from two-bar search, geocodes from string address + if (queryParams.address && !queryParams.page) { + console.log('in address conditional, ', queryParams); + queryParams.name = queryParams.address; + const geocodeParams = `?key=${process.env.PLACES_API_KEY}&address=${slugify( + queryParams.address + )}`; + + let geocodeResponse; + try { + geocodeResponse = await axios.get( + `https://maps.googleapis.com/maps/api/geocode/json${geocodeParams}` + ); + } catch (err) { + console.log( + `Geocode failed to be found at list-venues.\nQuery Params: ${JSON.stringify( + queryParams + )}` + ); + return next(err); + } + + const statusCode = geocodeResponse.data.status; + if (statusCode === 'ZERO_RESULTS') { + return res.status(404).json({ keywords: 'Address not found' }); + } else if (statusCode === 'OVER_QUERY_LIMIT') { + return next(new Error('Over query limit with Google Places API')); + } else if (statusCode === 'REQUEST_DENIED') { + return next(new Error('Request denied with Google Places API')); + } else if (statusCode === 'INVALID_REQUEST') { + return next(new Error('Invalid request with Google Places API')); + } else if (statusCode === 'UNKNOWN_ERROR') { + return next(new Error('Unknown error with Google Places API')); + } + + coordinates = [ + geocodeResponse.data.results[0].geometry.location.lat, + geocodeResponse.data.results[0].geometry.location.lng + ]; + } //end address geocode + + let venuesFilters = {}; + let dbVenuesFilters = {}; + + /* + * Legacy filter string building function, + * has a critical defect condition where if + * no > yes but yes is at least 1, then there + * would be a false match. + */ + if (queryParams.entranceScore) { + venuesFilters.entranceScore = parseFloat(queryParams.entranceScore); + //{ $gte: parseFloat(queryParams.entranceScore) }; + } + + if (queryParams.interiorScore) { + venuesFilters.interiorScore = parseFloat(queryParams.interiorScore); + //{ $gte: parseFloat(queryParams.interiorScore) }; + } + + if (queryParams.restroomScore) { + venuesFilters.restroomScore = parseFloat(queryParams.restroomScore); + //{ $gte: parseFloat(queryParams.restroomScore) }; + } + + if (queryParams.allowsGuideDog) { + venuesFilters.allowsGuideDog = parseFloat(queryParams.allowsGuideDog); + + const allowsGuideDog = parseFloat(queryParams.allowsGuideDog) === 1; + if (allowsGuideDog) { + dbVenuesFilters['allowsGuideDog.yes'] = { $gte: 1 }; + } else { + dbVenuesFilters['allowsGuideDog.no'] = { $gte: 1 }; + } + } + + if (queryParams.hasParking) { + venuesFilters.hasParking = queryParams.hasParking; + + const hasParking = parseFloat(queryParams.hasParking) === 1; + if (hasParking) { + dbVenuesFilters['hasParking.yes'] = { $gte: 1 }; + } else { + dbVenuesFilters['hasParking.no'] = { $gte: 1 }; + } + } + + /* + * Not used + * + if (queryParams.hasRamp) { + const hasRamp = parseFloat(queryParams.hasRamp) === 1; + if (hasRamp) { + venuesFilters['hasRamp.yes'] = { $gte: 1 }; + } else { + venuesFilters['hasRamp.no'] = { $gte: 1 }; + } + } + + if (queryParams.hasSecondEntry) { + const hasSecondEntry = parseFloat(queryParams.hasSecondEntry) === 1; + if (hasSecondEntry) { + venuesFilters['hasSecondEntry.yes'] = { $gte: 1 }; + } else { + venuesFilters['hasSecondEntry.no'] = { $gte: 1 }; + } + } + + if (queryParams.hasWellLit) { + const hasWellLit = parseFloat(queryParams.hasWellLit) === 1; + if (hasWellLit) { + venuesFilters['hasWellLit.yes'] = { $gte: 1 }; + } else { + venuesFilters['hasWellLit.no'] = { $gte: 1 }; + } + } + + if (queryParams.isQuiet) { + const isQuiet = parseFloat(queryParams.isQuiet) === 1; + if (isQuiet) { + venuesFilters['isQuiet.yes'] = { $gte: 1 }; + } else { + venuesFilters['isQuiet.no'] = { $gte: 1 }; + } + } + + if (queryParams.isSpacious) { + const isSpacious = parseFloat(queryParams.isSpacious) === 1; + if (isSpacious) { + venuesFilters['isSpacious.yes'] = { $gte: 1 }; + } else { + venuesFilters['isSpacious.no'] = { $gte: 1 }; + } + } + + if (queryParams.steps) { + if (parseFloat(queryParams.steps) === 0) { + venuesFilters['steps.zero'] = { $gte: 1 }; + } else if (parseFloat(queryParams.steps) === 1) { + venuesFilters['steps.one'] = { $gte: 1 }; + } else if (parseFloat(queryParams.steps) === 2) { + venuesFilters['steps.two'] = { $gte: 1 }; + } else if (parseFloat(queryParams.steps) === 3) { + venuesFilters['steps.moreThanTwo'] = { $gte: 1 }; + } + } + * + */ + + let dataResponse; + + /* + * Legacy filtering function that searches solely on + * AXS Venue data and provides it's own pagination of 20 + * UPDATED 05/2020 TO SUPPORT FILTER ONLY SELF SEARCH + */ + if (!isEmpty(venuesFilters) && isEmpty(queryParams.name)) { + console.log('>> Performing DB search'); + /* + if (queryParams.name) { + //performs literal name match against AXS Venue name + venuesFilters.name = { $regex: queryParams.name, $options: 'i' }; + } + */ + + dbVenuesFilters.location = { + $near: { + $geometry: { + type: 'Point', + coordinates: [coordinates[1], coordinates[0]] + }, + $maxDistance: 50000 + } + }; + + if (queryParams.type) { + dbVenuesFilters.types = queryParams.type; + } + + dbVenuesFilters.isArchived = false; + + let page = 1; + if (isNumber(queryParams.page)) { + page = queryParams.page; + } + + const pageLimit = + 'entranceScore' in venuesFilters || + 'interiorScore' in venuesFilters || + 'restroomScore' in venuesFilters + ? 80 + : 20; + + if (page > 0) { + page -= 1; + } else { + return res + .status(400) + .json({ page: 'Should be equal to or greater than 1' }); + } + + let total; + let venues; + try { + [venues, total] = await Promise.all([ + Venue.find( + dbVenuesFilters + /*,'address allowsGuideDog hasParking hasSecondEntry hasWellLit isQuiet isSpacious location name photos placeId steps types'*/ + ) + .skip(page * pageLimit) + .limit(pageLimit), + Venue.find(dbVenuesFilters).count() + /*TODO: count is deprecated in favor of countDocuments, but that does not support $near + would need to move to GeoWithin but that does not return sorted results + */ + ]); + } catch (err) { + console.log( + `Venues failed to be found or count at list-venues.\nvenuesQuery: ${JSON.stringify( + dbVenuesFilters + )}` + ); + console.log(err); + return next(err); + } + + venues = venues.map((venue) => + Object.assign({}, venue.toObject(), { + id: venue._id, + _id: undefined, + location: venue.coordinates + }) + ); + + //+ADDED + //Perform ratings logic on all returned venues + console.log('Raw venues count: ' + venues.length); + venues = venues.filter((venue) => { + //console.log('In scoring assignment'); + let scoring; + //calculate entranceScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); + venue.entranceScore = scoring.ratingLevel; + venue.entranceGlyphs = scoring.ratingGlyphs; + + //calculate interiorScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('interior', venue); + venue.interiorScore = scoring.ratingLevel; + venue.interiorGlyphs = scoring.ratingGlyphs; + + //calculate restroomScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); + venue.restroomScore = scoring.ratingLevel; + venue.restroomGlyphs = scoring.ratingGlyphs; + + venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( + venue.entranceScore, + venue.interiorScore, + venue.restroomScore + ); + + let passesValidation = true; + if ('entranceScore' in venuesFilters) { + if ( + !venue.entranceScore || + venue.entranceScore < venuesFilters.entranceScore + ) { + passesValidation = false; + } + } + + if (passesValidation && 'interiorScore' in venuesFilters) { + if ( + !venue.interiorScore || + venue.interiorScore < venuesFilters.interiorScore + ) { + passesValidation = false; + } + } + + if (passesValidation && 'restroomScore' in venuesFilters) { + if ( + !venue.restroomScore || + venue.restroomScore < venuesFilters.restroomScore + ) { + passesValidation = false; + } + } + + if (passesValidation) { + return venue; + } + }); + + const lastPage = Math.ceil(total / pageLimit); + let nextPage; + if (lastPage > 0) { + page += 1; + if (page > lastPage || page > 3) { + return res.status(400).json({ + page: `Should be equal to or less than ${lastPage > 3 ? 3 : lastPage}` + }); + } + } + + dataResponse = { + nextPage, + results: venues + }; + /* + * End legacy filter + */ + } else { + console.log('>> Performing Google search'); + + /* + * Perform Google search when there text entered or no filters selected + */ + let nearbyParams = `?key=${process.env.PLACES_API_KEY}`; + let searchType = queryParams.name ? 'textsearch' : 'nearbysearch'; + + if (!queryParams.page) { + nearbyParams = `${nearbyParams}&location=${coordinates[0]},${ + coordinates[1] + //}&rankby=distance`; + }`; + + if (queryParams.name) { + //nearbyParams = `${nearbyParams}&keyword=${queryParams.name}`; + nearbyParams = `${nearbyParams}&query=${queryParams.name}&radius=5000`; + } else { + //empty search, such as on load + nearbyParams = `${nearbyParams}&rankby=distance`; + } + + if (queryParams.type) { + nearbyParams = `${nearbyParams}&type=${queryParams.type}`; + } else { + nearbyParams = `${nearbyParams}&type=establishment`; + } + } else { + nearbyParams = `${nearbyParams}&pagetoken=${queryParams.page}`; + } + + if (queryParams.rankby) { + nearbyParams = `${nearbyParams}&rankby=${queryParams.rankby}`; + } + if (queryParams.opennow) { + nearbyParams = `${nearbyParams}&opennow=${queryParams.opennow}`; + } + if (queryParams.minprice) { + nearbyParams = `${nearbyParams}&minprice=${queryParams.minprice}`; + } + if (queryParams.maxprice) { + nearbyParams = `${nearbyParams}&maxprice=${queryParams.maxprice}`; + } + + let placesResponse; + try { + console.log( + 'performing google search: ' + + `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}` + ); + placesResponse = await axios.get( + `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}` + ); + } catch (err) { + console.log( + `Places failed to be found at list-venues.\nQuery Params: ${JSON.stringify( + queryParams + )}` + ); + return next(err); + } + + const statusCode = placesResponse.data.status; + if (statusCode === 'OVER_QUERY_LIMIT') { + return next(new Error('Over query limit with Google Places API')); + } else if (statusCode === 'REQUEST_DENIED') { + return next(new Error('Request denied with Google Places API')); + } else if (statusCode === 'INVALID_REQUEST') { + return next(new Error('Invalid request with Google Places API')); + } else if (statusCode === 'UNKNOWN_ERROR') { + return next(new Error('Unknown error with Google Places API')); + } + //do we need to check for 0? + + if (placesResponse.data.results.length == 1) { + if (placesResponse.data.results[0].types[0] == 'locality') { + console.log( + 'Found a city only: ', + placesResponse.data.results[0].geometry.location + ); + //TODO: redo search with new coordinates and no query/name or change/add "places in " to the first part of the string + } + } + + //Format Google Places results and get array of IDs + let places = []; + const placesIds = []; + placesResponse.data.results.forEach((place) => { + let photo = ''; + if (place.photos) { + photo = `https://maps.googleapis.com/maps/api/place/photo?key=${ + process.env.PLACES_API_KEY + }&maxwidth=300&photoreference=${place.photos[0].photo_reference}`; + } + + places.push({ + //address: place.vicinity, + address: place.formatted_address, + location: { + lat: place.geometry.location.lat, + lng: place.geometry.location.lng + }, + name: place.name, + photo, + placeId: place.place_id, + types: place.types + }); + placesIds.push(place.place_id); + }); + + //Use array of Google Place IDs to find AXS Venues + let venues; + try { + venues = await Venue.find({ placeId: { $in: placesIds } }); + } catch (err) { + console.log( + `Venues failed to be found at list-venues.\nPlaces ids: [${placesIds}]` + ); + return next(err); + } + + //Perform ratings logic on all returned venues + venues.forEach((venue) => { + //console.log('In scoring assignment'); + let scoring; + //calculate entranceScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); + venue.entranceScore = scoring.ratingLevel; + venue.entranceGlyphs = scoring.ratingGlyphs; + + //calculate interiorScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('interior', venue); + venue.interiorScore = scoring.ratingLevel; + venue.interiorGlyphs = scoring.ratingGlyphs; + + //calculate restroomScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); + venue.restroomScore = scoring.ratingLevel; + venue.restroomGlyphs = scoring.ratingGlyphs; + + venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( + venue.entranceScore, + venue.interiorScore, + venue.restroomScore + ); + }); + + //Filter out, remove, Google Places that are not AXS Venues + // Can't use hasOwnProperty() on mongoose model objects // + if (!isEmpty(venuesFilters)) { + console.log('>> Performing secondary DB filtering'); + places = places.filter((place) => { + const venue = find(venues, (venue) => venue.placeId === place.placeId); + if (venue) { + //console.log('In verification of filters'); + let passesValidation = true; + if (passesValidation && 'allowsGuideDog' in venuesFilters) { + if ( + !venue.allowsGuideDog || + venue.allowsGuideDog.yes < venue.allowsGuideDog.no || + venue.allowsGuideDog.yes == 0 + ) { + passesValidation = false; + } + } + + if (passesValidation && 'hasParking' in venuesFilters) { + if ( + !venue.hasParking || + venue.hasParking.yes < venue.hasParking.no || + venue.hasParking.yes == 0 + ) { + passesValidation = false; + } + } + + if (passesValidation && 'entranceScore' in venuesFilters) { + if ( + !venue.entranceScore || + venue.entranceScore < venuesFilters.entranceScore + ) { + passesValidation = false; + } + } + + if (passesValidation && 'interiorScore' in venuesFilters) { + if ( + !venue.interiorScore || + venue.interiorScore < venuesFilters.interiorScore + ) { + passesValidation = false; + } + } + + if (passesValidation && 'restroomScore' in venuesFilters) { + if ( + !venue.restroomScore || + venue.restroomScore < venuesFilters.restroomScore + ) { + passesValidation = false; + } + } + + if (passesValidation) { + return venue; + } + } + }); + } //end filtering Google results + + // + places = places.map((place) => { + const venue = find(venues, (venue) => venue.placeId === place.placeId); + if (venue) { + return Object.assign({}, place, { + //new expanded fields + hasPermanentRamp: venue.hasPermanentRamp, + hasPortableRamp: venue.hasPortableRamp, + hasWideEntrance: venue.hasWideEntrance, + hasAccessibleTableHeight: venue.hasAccessibleTableHeight, + hasAccessibleElevator: venue.hasAccessibleElevator, + hasInteriorRamp: venue.hasInteriorRamp, + hasSwingInDoor: venue.hasSwingInDoor, + hasSwingOutDoor: venue.hasSwingOutDoor, + hasLargeStall: venue.hasLargeStall, + hasSupportAroundToilet: venue.hasSupportAroundToilet, + hasLoweredSinks: venue.hasLoweredSinks, + + entranceScore: venue.entranceScore, + entranceGlyphs: venue.entranceGlyphs, + interiorScore: venue.interiorScore, + interiorGlyphs: venue.interiorGlyphs, + restroomScore: venue.restroomScore, + restroomGlyphs: venue.restroomGlyphs, + mapMarkerScore: venue.mapMarkerScore, + + //original fields + allowsGuideDog: venue.allowsGuideDog, + //_bathroomScore: venue.bathroomScore, + //_entryScore: venue.entryScore, + hasParking: venue.hasParking, + hasSecondEntry: venue.hasSecondEntry, + hasWellLit: venue.hasWellLit, + isQuiet: venue.isQuiet, + isSpacious: venue.isSpacious, + steps: venue.steps + }); + } + + //venue not found + return Object.assign({}, place, { + //new expanded fields + hasPermanentRamp: { yes: 0, no: 0 }, + hasPortableRamp: { yes: 0, no: 0 }, + hasWideEntrance: { yes: 0, no: 0 }, + hasAccessibleTableHeight: { yes: 0, no: 0 }, + hasAccessibleElevator: { yes: 0, no: 0 }, + hasInteriorRamp: { yes: 0, no: 0 }, + hasSwingInDoor: { yes: 0, no: 0 }, + hasSwingOutDoor: { yes: 0, no: 0 }, + hasLargeStall: { yes: 0, no: 0 }, + hasSupportAroundToilet: { yes: 0, no: 0 }, + hasLoweredSinks: { yes: 0, no: 0 }, + interiorScore: 0, + interiorGlyphs: 'interior', + restroomScore: 0, + restroomGlyphs: 'restroom', + entranceScore: 0, + entranceGlyphs: 'entrylg', + mapMarkerScore: 0, + + //original fields + allowsGuideDog: { yes: 0, no: 0 }, + //_bathroomReviews: 0, + //_bathroomScore: null, + //_entryReviews: 0, + //_entryScore: null, + hasParking: { yes: 0, no: 0 }, + hasSecondEntry: { yes: 0, no: 0 }, + hasWellLit: { yes: 0, no: 0 }, + isQuiet: { yes: 0, no: 0 }, + isSpacious: { yes: 0, no: 0 }, + steps: { + zero: 0, + one: 0, + two: 0, + moreThanTwo: 0 + } + }); + }); + + dataResponse = { + nextPage: placesResponse.data.next_page_token, + results: places + }; + } //ends legacy filter logic, false conditional + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/venues/validations.js b/src/routes/venues/validations.js index 6d393cc..a234600 100644 --- a/src/routes/venues/validations.js +++ b/src/routes/venues/validations.js @@ -1,154 +1,154 @@ -const { isEmpty } = require('lodash'); - -const { isNumber } = require('../../helpers'); -const { placesTypes } = require('../../helpers/constants'); - -module.exports = { - validateListVenues(queryParams) { - const errors = {}; - - if (!queryParams.location) { - errors.location = 'Is required'; - } else { - const location = queryParams.location.split(','); - - if (location.length !== 2) { - errors.location = 'Should have two coordinates'; - } else if (!location[0]) { - errors.location = 'Latitude is required'; - } else if (!isNumber(location[0])) { - errors.location = 'Latitude should be a number'; - } else if ( - parseFloat(location[0]) < -90 || - parseFloat(location[0]) > 90 - ) { - errors.location = 'Latitude value out of bounds'; - } else if (!location[1]) { - errors.location = 'Longitude is required'; - } else if (!isNumber(location[1])) { - errors.location = 'Longitude should be a number'; - } else if ( - parseFloat(location[1]) < -180 || - parseFloat(location[1]) > 180 - ) { - errors.location = 'Longitude value out of bounds'; - } - } - - if (queryParams.bathroomScore) { - if (!isNumber(queryParams.bathroomScore)) { - errors.bathroomScore = 'Should be a number'; - } else if ( - parseFloat(queryParams.bathroomScore) < 1 || - parseFloat(queryParams.bathroomScore) > 5 - ) { - errors.bathroomScore = 'Should be between 1 and 5'; - } - } - - if (queryParams.entryScore) { - if (!isNumber(queryParams.entryScore)) { - errors.entryScore = 'Should be a number'; - } else if ( - parseFloat(queryParams.entryScore) < 1 || - parseFloat(queryParams.entryScore) > 5 - ) { - errors.entryScore = 'Should be between 1 and 5'; - } - } - - if (queryParams.allowsGuideDog) { - if (!isNumber(queryParams.allowsGuideDog)) { - errors.allowsGuideDog = 'Should be a number'; - } else if ( - parseFloat(queryParams.allowsGuideDog) !== 0 && - parseFloat(queryParams.allowsGuideDog) !== 1 - ) { - errors.allowsGuideDog = 'Should be 0 or 1'; - } - } - - if (queryParams.hasParking) { - if (!isNumber(queryParams.hasParking)) { - errors.hasParking = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasParking) !== 0 && - parseFloat(queryParams.hasParking) !== 1 - ) { - errors.hasParking = 'Should be 0 or 1'; - } - } - - if (queryParams.hasRamp) { - if (!isNumber(queryParams.hasRamp)) { - errors.hasRamp = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasRamp) !== 0 && - parseFloat(queryParams.hasRamp) !== 1 - ) { - errors.hasRamp = 'Should be 0 or 1'; - } - } - - if (queryParams.hasSecondEntry) { - if (!isNumber(queryParams.hasSecondEntry)) { - errors.hasSecondEntry = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasSecondEntry) !== 0 && - parseFloat(queryParams.hasSecondEntry) !== 1 - ) { - errors.hasSecondEntry = 'Should be 0 or 1'; - } - } - - if (queryParams.hasWellLit) { - if (!isNumber(queryParams.hasWellLit)) { - errors.hasWellLit = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasWellLit) !== 0 && - parseFloat(queryParams.hasWellLit) !== 1 - ) { - errors.hasWellLit = 'Should be 0 or 1'; - } - } - - if (queryParams.isQuiet) { - if (!isNumber(queryParams.isQuiet)) { - errors.isQuiet = 'Should be a number'; - } else if ( - parseFloat(queryParams.isQuiet) !== 0 && - parseFloat(queryParams.isQuiet) !== 1 - ) { - errors.isQuiet = 'Should be 0 or 1'; - } - } - - if (queryParams.isSpacious) { - if (!isNumber(queryParams.isSpacious)) { - errors.isSpacious = 'Should be a number'; - } else if ( - parseFloat(queryParams.isSpacious) !== 0 && - parseFloat(queryParams.isSpacious) !== 1 - ) { - errors.isSpacious = 'Should be 0 or 1'; - } - } - - if (queryParams.steps) { - if (!isNumber(queryParams.steps)) { - errors.steps = 'Should be a number'; - } else if ( - parseFloat(queryParams.steps) < 0 || - parseFloat(queryParams.steps) > 3 - ) { - errors.steps = 'Should be between 0 and 3'; - } - } - - if (queryParams.type && !placesTypes.includes(queryParams.type)) { - errors.type = 'Should be a valid type'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); + +const { isNumber } = require('../../helpers'); +const { placesTypes } = require('../../helpers/constants'); + +module.exports = { + validateListVenues(queryParams) { + const errors = {}; + + if (!queryParams.location) { + errors.location = 'Is required'; + } else { + const location = queryParams.location.split(','); + + if (location.length !== 2) { + errors.location = 'Should have two coordinates'; + } else if (!location[0]) { + errors.location = 'Latitude is required'; + } else if (!isNumber(location[0])) { + errors.location = 'Latitude should be a number'; + } else if ( + parseFloat(location[0]) < -90 || + parseFloat(location[0]) > 90 + ) { + errors.location = 'Latitude value out of bounds'; + } else if (!location[1]) { + errors.location = 'Longitude is required'; + } else if (!isNumber(location[1])) { + errors.location = 'Longitude should be a number'; + } else if ( + parseFloat(location[1]) < -180 || + parseFloat(location[1]) > 180 + ) { + errors.location = 'Longitude value out of bounds'; + } + } + + if (queryParams.bathroomScore) { + if (!isNumber(queryParams.bathroomScore)) { + errors.bathroomScore = 'Should be a number'; + } else if ( + parseFloat(queryParams.bathroomScore) < 1 || + parseFloat(queryParams.bathroomScore) > 5 + ) { + errors.bathroomScore = 'Should be between 1 and 5'; + } + } + + if (queryParams.entryScore) { + if (!isNumber(queryParams.entryScore)) { + errors.entryScore = 'Should be a number'; + } else if ( + parseFloat(queryParams.entryScore) < 1 || + parseFloat(queryParams.entryScore) > 5 + ) { + errors.entryScore = 'Should be between 1 and 5'; + } + } + + if (queryParams.allowsGuideDog) { + if (!isNumber(queryParams.allowsGuideDog)) { + errors.allowsGuideDog = 'Should be a number'; + } else if ( + parseFloat(queryParams.allowsGuideDog) !== 0 && + parseFloat(queryParams.allowsGuideDog) !== 1 + ) { + errors.allowsGuideDog = 'Should be 0 or 1'; + } + } + + if (queryParams.hasParking) { + if (!isNumber(queryParams.hasParking)) { + errors.hasParking = 'Should be a number'; + } else if ( + parseFloat(queryParams.hasParking) !== 0 && + parseFloat(queryParams.hasParking) !== 1 + ) { + errors.hasParking = 'Should be 0 or 1'; + } + } + + if (queryParams.hasRamp) { + if (!isNumber(queryParams.hasRamp)) { + errors.hasRamp = 'Should be a number'; + } else if ( + parseFloat(queryParams.hasRamp) !== 0 && + parseFloat(queryParams.hasRamp) !== 1 + ) { + errors.hasRamp = 'Should be 0 or 1'; + } + } + + if (queryParams.hasSecondEntry) { + if (!isNumber(queryParams.hasSecondEntry)) { + errors.hasSecondEntry = 'Should be a number'; + } else if ( + parseFloat(queryParams.hasSecondEntry) !== 0 && + parseFloat(queryParams.hasSecondEntry) !== 1 + ) { + errors.hasSecondEntry = 'Should be 0 or 1'; + } + } + + if (queryParams.hasWellLit) { + if (!isNumber(queryParams.hasWellLit)) { + errors.hasWellLit = 'Should be a number'; + } else if ( + parseFloat(queryParams.hasWellLit) !== 0 && + parseFloat(queryParams.hasWellLit) !== 1 + ) { + errors.hasWellLit = 'Should be 0 or 1'; + } + } + + if (queryParams.isQuiet) { + if (!isNumber(queryParams.isQuiet)) { + errors.isQuiet = 'Should be a number'; + } else if ( + parseFloat(queryParams.isQuiet) !== 0 && + parseFloat(queryParams.isQuiet) !== 1 + ) { + errors.isQuiet = 'Should be 0 or 1'; + } + } + + if (queryParams.isSpacious) { + if (!isNumber(queryParams.isSpacious)) { + errors.isSpacious = 'Should be a number'; + } else if ( + parseFloat(queryParams.isSpacious) !== 0 && + parseFloat(queryParams.isSpacious) !== 1 + ) { + errors.isSpacious = 'Should be 0 or 1'; + } + } + + if (queryParams.steps) { + if (!isNumber(queryParams.steps)) { + errors.steps = 'Should be a number'; + } else if ( + parseFloat(queryParams.steps) < 0 || + parseFloat(queryParams.steps) > 3 + ) { + errors.steps = 'Should be between 0 and 3'; + } + } + + if (queryParams.type && !placesTypes.includes(queryParams.type)) { + errors.type = 'Should be a valid type'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/scripts/db/import-events.js b/src/scripts/db/import-events.js index 6ad0a17..65fa480 100644 --- a/src/scripts/db/import-events.js +++ b/src/scripts/db/import-events.js @@ -1,154 +1,154 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); - -const oldEventsSchema = require('./old-schemas/event'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const oldEvent = oldDb.model('events', oldEventsSchema); - - let totalOldEvents; - try { - totalOldEvents = await oldEvent.count({ name: { $ne: '' } }); - } catch (error) { - console.log('Old events failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old events: ${totalOldEvents}`); - - console.time('createEvents'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldEvents; - try { - oldEvents = await oldEvent - .find({ name: { $ne: '' } }) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old events failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const Event = db.model('Event', eventSchema); - - const createEvents = []; - for (let oldEventItem of oldEvents) { - let participants = oldEventItem.members.map(member => member.user); - participants = participants.filter( - p => p.toString() !== oldEventItem.creator.toString() - ); - - const eventData = { - _id: oldEventItem.id, - createdAt: oldEventItem.created_at, - description: oldEventItem.description.substring(0, 300), - endDate: oldEventItem.event_end, - managers: [oldEventItem.creator], - name: oldEventItem.name, - participants, - participantsGoal: oldEventItem.participant_goal - ? oldEventItem.participant_goal > 1000 - ? 1000 - : oldEventItem.participant_goal - : 1, - poster: oldEventItem.image, - reviewsGoal: oldEventItem.mapping_goal - ? oldEventItem.mapping_goal > 10000 - ? 10000 - : oldEventItem.mapping_goal - : 1, - startDate: oldEventItem.event_start, - teams: oldEventItem.teams, - updatedAt: oldEventItem.updated_at, - venue: oldEventItem.location - }; - - createEvents.push(Event.create(eventData)); - } - - try { - await Promise.all(createEvents); - } catch (error) { - console.log( - `Events failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldEvents.length; - console.log(i); - } while (i < totalOldEvents); - - console.timeEnd('createEvents'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { eventSchema } = require('../../models/event'); + +const oldEventsSchema = require('./old-schemas/event'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const oldEvent = oldDb.model('events', oldEventsSchema); + + let totalOldEvents; + try { + totalOldEvents = await oldEvent.count({ name: { $ne: '' } }); + } catch (error) { + console.log('Old events failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old events: ${totalOldEvents}`); + + console.time('createEvents'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldEvents; + try { + oldEvents = await oldEvent + .find({ name: { $ne: '' } }) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old events failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const Event = db.model('Event', eventSchema); + + const createEvents = []; + for (let oldEventItem of oldEvents) { + let participants = oldEventItem.members.map((member) => member.user); + participants = participants.filter( + (p) => p.toString() !== oldEventItem.creator.toString() + ); + + const eventData = { + _id: oldEventItem.id, + createdAt: oldEventItem.created_at, + description: oldEventItem.description.substring(0, 300), + endDate: oldEventItem.event_end, + managers: [oldEventItem.creator], + name: oldEventItem.name, + participants, + participantsGoal: oldEventItem.participant_goal + ? oldEventItem.participant_goal > 1000 + ? 1000 + : oldEventItem.participant_goal + : 1, + poster: oldEventItem.image, + reviewsGoal: oldEventItem.mapping_goal + ? oldEventItem.mapping_goal > 10000 + ? 10000 + : oldEventItem.mapping_goal + : 1, + startDate: oldEventItem.event_start, + teams: oldEventItem.teams, + updatedAt: oldEventItem.updated_at, + venue: oldEventItem.location + }; + + createEvents.push(Event.create(eventData)); + } + + try { + await Promise.all(createEvents); + } catch (error) { + console.log( + `Events failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldEvents.length; + console.log(i); + } while (i < totalOldEvents); + + console.timeEnd('createEvents'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-reviews.js b/src/scripts/db/import-reviews.js index 4f36291..1e125c3 100644 --- a/src/scripts/db/import-reviews.js +++ b/src/scripts/db/import-reviews.js @@ -1,149 +1,149 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { reviewSchema } = require('../../models/review'); - -const oldReviewSchema = require('./old-schemas/review'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldReview = oldDb.model('reviews', oldReviewSchema); - - let totalOldReviews; - try { - totalOldReviews = await OldReview.count(); - } catch (error) { - console.log('Old reviews failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old reviews: ${totalOldReviews}`); - - console.time('createReviews'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldReviews; - try { - oldReviews = await OldReview.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old reviews failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const Review = db.model('Review', reviewSchema); - - const createReviews = []; - for (let oldReview of oldReviews) { - if (oldReview.venue_id && oldReview.user_id) { - const reviewData = { - _id: oldReview.id, - allowsGuideDog: oldReview.guidedog, - createdAt: oldReview.created_at, - bathroomScore: oldReview.bathroom, - entryScore: oldReview.entry, - event: oldReview.event, - hasParking: oldReview.parking, - hasRamp: oldReview.ramp, - hasSecondEntry: oldReview.secondentrance, - hasWellLit: oldReview.welllit, - isQuiet: oldReview.quiet, - isSpacious: oldReview.spacious, - steps: oldReview.steps, - team: oldReview.team, - updatedAt: oldReview.updated_at, - user: oldReview.user_id, - venue: oldReview.venue_id - }; - - if (oldReview.comment && oldReview.comment.length <= 300) { - reviewData.comments = oldReview.comment; - } - - createReviews.push(Review.create(reviewData)); - } - } - - try { - await Promise.all(createReviews); - } catch (error) { - console.log( - `Reviews failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldReviews.length; - console.log(i); - } while (i < totalOldReviews); - - console.timeEnd('createReviews'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { reviewSchema } = require('../../models/review'); + +const oldReviewSchema = require('./old-schemas/review'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldReview = oldDb.model('reviews', oldReviewSchema); + + let totalOldReviews; + try { + totalOldReviews = await OldReview.count(); + } catch (error) { + console.log('Old reviews failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old reviews: ${totalOldReviews}`); + + console.time('createReviews'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldReviews; + try { + oldReviews = await OldReview.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old reviews failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const Review = db.model('Review', reviewSchema); + + const createReviews = []; + for (let oldReview of oldReviews) { + if (oldReview.venue_id && oldReview.user_id) { + const reviewData = { + _id: oldReview.id, + allowsGuideDog: oldReview.guidedog, + createdAt: oldReview.created_at, + bathroomScore: oldReview.bathroom, + entryScore: oldReview.entry, + event: oldReview.event, + hasParking: oldReview.parking, + hasRamp: oldReview.ramp, + hasSecondEntry: oldReview.secondentrance, + hasWellLit: oldReview.welllit, + isQuiet: oldReview.quiet, + isSpacious: oldReview.spacious, + steps: oldReview.steps, + team: oldReview.team, + updatedAt: oldReview.updated_at, + user: oldReview.user_id, + venue: oldReview.venue_id + }; + + if (oldReview.comment && oldReview.comment.length <= 300) { + reviewData.comments = oldReview.comment; + } + + createReviews.push(Review.create(reviewData)); + } + } + + try { + await Promise.all(createReviews); + } catch (error) { + console.log( + `Reviews failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldReviews.length; + console.log(i); + } while (i < totalOldReviews); + + console.timeEnd('createReviews'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-teams.js b/src/scripts/db/import-teams.js index 4334d0b..b9393ce 100644 --- a/src/scripts/db/import-teams.js +++ b/src/scripts/db/import-teams.js @@ -1,270 +1,270 @@ -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); - -require('dotenv').config(); - -const { reviewSchema } = require('../../models/review'); -const { teamSchema } = require('../../models/team'); - -const oldTeamSchema = require('./old-schemas/team'); - -mongoose.Promise = global.Promise; - -const s3 = new aws.S3(); - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldTeam = oldDb.model('teams', oldTeamSchema); - - let totalOldTeams; - try { - totalOldTeams = await OldTeam.count(); - } catch (error) { - console.log('Old teams failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old teams: ${totalOldTeams}`); - - const Team = db.model('Team', teamSchema); - - console.time('createTeams'); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let oldTeams; - try { - oldTeams = await OldTeam.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old teams failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const createTeams = []; - const uploadTeamsAvatars = []; - for (let oldTeam of oldTeams) { - if (oldTeam.name) { - const members = oldTeam.members.filter( - m => m.toString() !== oldTeam.creator.toString() - ); - const teamData = { - _id: oldTeam.id, - createdAt: oldTeam.created_at, - events: oldTeam.events, - managers: [oldTeam.creator], - members: members, - name: - oldTeam.name.length > 35 - ? oldTeam.name.substring(0, 35) - : oldTeam.name, - updatedAt: oldTeam.updated_at - }; - - if (oldTeam.description) { - teamData.description = - oldTeam.description.length <= 300 - ? oldTeam.description - : oldTeam.description.substring(0, 300); - } - - if (oldTeam.image && !oldTeam.image.includes('icon_team.png')) { - let avatarImage; - try { - avatarImage = await jimp.read(encodeURI(oldTeam.image)); - } catch (err) { - console.log('Old team avatar image failed to be read'); - console.log(err); - await closeConnections(db, oldDb); - } - - if (avatarImage) { - const avatarExtension = avatarImage.getExtension(); - const avatarFileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${avatarExtension}`; - - if ( - avatarExtension === 'png' || - avatarExtension === 'jpeg' || - avatarExtension === 'jpg' || - avatarExtension === 'bmp' - ) { - teamData.avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/teams/avatars/${avatarFileName}`; - avatarImage - .cover(400, 400) - .quality(85) - .getBuffer( - avatarImage.getMIME(), - async (err, avatarBuffer) => { - if (err) { - console.log('Old team avatar buffer failed to be read'); - console.log(err); - await closeConnections(db, oldDb); - } - - uploadTeamsAvatars.push( - s3 - .putObject({ - ACL: 'public-read', - Body: avatarBuffer, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: avatarImage.getMIME(), - Key: `teams/avatars/${avatarFileName}` - }) - .promise() - ); - } - ); - } - } - } - - createTeams.push(Team.create(teamData)); - } - } - - try { - await Promise.all([...createTeams, ...uploadTeamsAvatars]); - } catch (error) { - console.log( - `Teams failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldTeams.length; - console.log(i); - } while (i < totalOldTeams); - - console.timeEnd('createTeams'); - - const Review = db.model('Review', reviewSchema); - - let totalTeams; - try { - totalTeams = await Team.count(); - } catch (error) { - console.log('Teams failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total teams: ${totalTeams}`); - - i = 0; - page = 0; - do { - let teams; - try { - teams = await Team.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Teams failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const updateTeams = []; - for (let team of teams) { - let teamReviews; - try { - teamReviews = await Review.find({ team: team.id }).count(); - } catch (err) { - console.log('Team reviews failed to be count'); - console.log(err); - await closeConnections(db, oldDb); - } - - team.reviewsAmount = teamReviews; - updateTeams.push(team.save()); - } - - try { - await Promise.all(updateTeams); - } catch (err) { - console.log( - `Teams failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + teams.length; - console.log(i); - } while (i < totalTeams); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); + +require('dotenv').config(); + +const { reviewSchema } = require('../../models/review'); +const { teamSchema } = require('../../models/team'); + +const oldTeamSchema = require('./old-schemas/team'); + +mongoose.Promise = global.Promise; + +const s3 = new aws.S3(); + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldTeam = oldDb.model('teams', oldTeamSchema); + + let totalOldTeams; + try { + totalOldTeams = await OldTeam.count(); + } catch (error) { + console.log('Old teams failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old teams: ${totalOldTeams}`); + + const Team = db.model('Team', teamSchema); + + console.time('createTeams'); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let oldTeams; + try { + oldTeams = await OldTeam.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old teams failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const createTeams = []; + const uploadTeamsAvatars = []; + for (let oldTeam of oldTeams) { + if (oldTeam.name) { + const members = oldTeam.members.filter( + (m) => m.toString() !== oldTeam.creator.toString() + ); + const teamData = { + _id: oldTeam.id, + createdAt: oldTeam.created_at, + events: oldTeam.events, + managers: [oldTeam.creator], + members: members, + name: + oldTeam.name.length > 35 + ? oldTeam.name.substring(0, 35) + : oldTeam.name, + updatedAt: oldTeam.updated_at + }; + + if (oldTeam.description) { + teamData.description = + oldTeam.description.length <= 300 + ? oldTeam.description + : oldTeam.description.substring(0, 300); + } + + if (oldTeam.image && !oldTeam.image.includes('icon_team.png')) { + let avatarImage; + try { + avatarImage = await jimp.read(encodeURI(oldTeam.image)); + } catch (err) { + console.log('Old team avatar image failed to be read'); + console.log(err); + await closeConnections(db, oldDb); + } + + if (avatarImage) { + const avatarExtension = avatarImage.getExtension(); + const avatarFileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${avatarExtension}`; + + if ( + avatarExtension === 'png' || + avatarExtension === 'jpeg' || + avatarExtension === 'jpg' || + avatarExtension === 'bmp' + ) { + teamData.avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/teams/avatars/${avatarFileName}`; + avatarImage + .cover(400, 400) + .quality(85) + .getBuffer( + avatarImage.getMIME(), + async (err, avatarBuffer) => { + if (err) { + console.log('Old team avatar buffer failed to be read'); + console.log(err); + await closeConnections(db, oldDb); + } + + uploadTeamsAvatars.push( + s3 + .putObject({ + ACL: 'public-read', + Body: avatarBuffer, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: avatarImage.getMIME(), + Key: `teams/avatars/${avatarFileName}` + }) + .promise() + ); + } + ); + } + } + } + + createTeams.push(Team.create(teamData)); + } + } + + try { + await Promise.all([...createTeams, ...uploadTeamsAvatars]); + } catch (error) { + console.log( + `Teams failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldTeams.length; + console.log(i); + } while (i < totalOldTeams); + + console.timeEnd('createTeams'); + + const Review = db.model('Review', reviewSchema); + + let totalTeams; + try { + totalTeams = await Team.count(); + } catch (error) { + console.log('Teams failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total teams: ${totalTeams}`); + + i = 0; + page = 0; + do { + let teams; + try { + teams = await Team.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Teams failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const updateTeams = []; + for (let team of teams) { + let teamReviews; + try { + teamReviews = await Review.find({ team: team.id }).count(); + } catch (err) { + console.log('Team reviews failed to be count'); + console.log(err); + await closeConnections(db, oldDb); + } + + team.reviewsAmount = teamReviews; + updateTeams.push(team.save()); + } + + try { + await Promise.all(updateTeams); + } catch (err) { + console.log( + `Teams failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + teams.length; + console.log(i); + } while (i < totalTeams); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-users.js b/src/scripts/db/import-users.js index ed75da7..55fdd69 100644 --- a/src/scripts/db/import-users.js +++ b/src/scripts/db/import-users.js @@ -1,275 +1,275 @@ -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -require('dotenv').config(); - -const { cleanSpaces } = require('../../helpers'); -const { reviewSchema } = require('../../models/review'); -const { userSchema } = require('../../models/user'); - -const oldUserSchema = require('./old-schemas/user'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldUser = oldDb.model('users', oldUserSchema); - - let totalOldUsers; - try { - totalOldUsers = await OldUser.count(); - } catch (error) { - console.log('Old users failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old users: ${totalOldUsers}`); - - const User = db.model('User', userSchema); - - console.time('createUsers'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldUsers; - try { - oldUsers = await OldUser.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old users failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const createUsers = []; - for (let oldUser of oldUsers) { - if (oldUser.isactive) { - const userData = { - _id: oldUser.id, - createdAt: oldUser.createdAt, - description: oldUser.description - ? cleanSpaces(oldUser.description) - : '', - email: oldUser.email, - events: oldUser.events, - facebookId: oldUser.facebookAuth, - firstName: - oldUser.name.first && cleanSpaces(oldUser.name.first) - ? cleanSpaces(oldUser.name.first) - : 'first', - hashedPassword: oldUser.hash, - isSubscribed: oldUser.newsletter, - lastName: - oldUser.name.last && cleanSpaces(oldUser.name.last) - ? cleanSpaces(oldUser.name.last) - : 'last', - phone: oldUser.phone ? cleanSpaces(oldUser.phone) : '', - showEmail: oldUser.showEmail, - showPhone: oldUser.showPhone, - teams: oldUser.teams, - updatedAt: oldUser.updatedAt, - username: `${slugify(oldUser.name.first)}-${slugify( - oldUser.name.last - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}` - }; - - switch (oldUser.disabilitytype.toLowerCase()) { - case 'audio': - userData.disabilities = ['audio']; - break; - - case 'other': - userData.disabilities = ['other']; - break; - - case 'private': - userData.disabilities = ['private']; - break; - - case 'visual': - userData.disabilities = ['vision']; - break; - - case 'wheelchair': - userData.disabilities = ['physical']; - break; - - default: - userData.disabilities = ['none']; - } - - switch (oldUser.gender.toLowerCase()) { - case 'female': - userData.gender = 'female'; - break; - - case 'male': - userData.gender = 'male'; - break; - - case 'other': - userData.gender = 'other'; - break; - - case 'transgender': - userData.gender = 'transgender'; - break; - - default: - userData.gender = 'private'; - } - - if (oldUser.zip && oldUser.zip.length <= 32) { - userData.zip = oldUser.zip; - } - - createUsers.push(User.create(userData)); - } - } - - try { - await Promise.all(createUsers); - } catch (error) { - console.log( - `Users failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldUsers.length; - console.log(i); - } while (i < totalOldUsers); - - console.timeEnd('createUsers'); - - const Review = db.model('Review', reviewSchema); - - let totalUsers; - try { - totalUsers = await User.count(); - } catch (error) { - console.log('Users failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total users: ${totalUsers}`); - - console.time('updateReviewsAmount'); - - i = 0; - page = 0; - do { - let users; - try { - users = await User.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Users failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const updateUsers = []; - for (let user of users) { - let userReviews; - try { - userReviews = await Review.find({ user: user.id }).count(); - } catch (err) { - console.log('User reviews failed to be count'); - console.log(err); - await closeConnections(db, oldDb); - } - - user.reviewsAmount = userReviews; - updateUsers.push(user.save()); - } - - try { - await Promise.all(updateUsers); - } catch (err) { - console.log( - `Users failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + users.length; - console.log(i); - } while (i < totalUsers); - - console.timeEnd('updateReviewsAmount'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +require('dotenv').config(); + +const { cleanSpaces } = require('../../helpers'); +const { reviewSchema } = require('../../models/review'); +const { userSchema } = require('../../models/user'); + +const oldUserSchema = require('./old-schemas/user'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldUser = oldDb.model('users', oldUserSchema); + + let totalOldUsers; + try { + totalOldUsers = await OldUser.count(); + } catch (error) { + console.log('Old users failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old users: ${totalOldUsers}`); + + const User = db.model('User', userSchema); + + console.time('createUsers'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldUsers; + try { + oldUsers = await OldUser.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old users failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const createUsers = []; + for (let oldUser of oldUsers) { + if (oldUser.isactive) { + const userData = { + _id: oldUser.id, + createdAt: oldUser.createdAt, + description: oldUser.description + ? cleanSpaces(oldUser.description) + : '', + email: oldUser.email, + events: oldUser.events, + facebookId: oldUser.facebookAuth, + firstName: + oldUser.name.first && cleanSpaces(oldUser.name.first) + ? cleanSpaces(oldUser.name.first) + : 'first', + hashedPassword: oldUser.hash, + isSubscribed: oldUser.newsletter, + lastName: + oldUser.name.last && cleanSpaces(oldUser.name.last) + ? cleanSpaces(oldUser.name.last) + : 'last', + phone: oldUser.phone ? cleanSpaces(oldUser.phone) : '', + showEmail: oldUser.showEmail, + showPhone: oldUser.showPhone, + teams: oldUser.teams, + updatedAt: oldUser.updatedAt, + username: `${slugify(oldUser.name.first)}-${slugify( + oldUser.name.last + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}` + }; + + switch (oldUser.disabilitytype.toLowerCase()) { + case 'audio': + userData.disabilities = ['audio']; + break; + + case 'other': + userData.disabilities = ['other']; + break; + + case 'private': + userData.disabilities = ['private']; + break; + + case 'visual': + userData.disabilities = ['vision']; + break; + + case 'wheelchair': + userData.disabilities = ['physical']; + break; + + default: + userData.disabilities = ['none']; + } + + switch (oldUser.gender.toLowerCase()) { + case 'female': + userData.gender = 'female'; + break; + + case 'male': + userData.gender = 'male'; + break; + + case 'other': + userData.gender = 'other'; + break; + + case 'transgender': + userData.gender = 'transgender'; + break; + + default: + userData.gender = 'private'; + } + + if (oldUser.zip && oldUser.zip.length <= 32) { + userData.zip = oldUser.zip; + } + + createUsers.push(User.create(userData)); + } + } + + try { + await Promise.all(createUsers); + } catch (error) { + console.log( + `Users failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldUsers.length; + console.log(i); + } while (i < totalOldUsers); + + console.timeEnd('createUsers'); + + const Review = db.model('Review', reviewSchema); + + let totalUsers; + try { + totalUsers = await User.count(); + } catch (error) { + console.log('Users failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total users: ${totalUsers}`); + + console.time('updateReviewsAmount'); + + i = 0; + page = 0; + do { + let users; + try { + users = await User.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Users failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const updateUsers = []; + for (let user of users) { + let userReviews; + try { + userReviews = await Review.find({ user: user.id }).count(); + } catch (err) { + console.log('User reviews failed to be count'); + console.log(err); + await closeConnections(db, oldDb); + } + + user.reviewsAmount = userReviews; + updateUsers.push(user.save()); + } + + try { + await Promise.all(updateUsers); + } catch (err) { + console.log( + `Users failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + users.length; + console.log(i); + } while (i < totalUsers); + + console.timeEnd('updateReviewsAmount'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-venues.js b/src/scripts/db/import-venues.js index 331c7b3..bf03081 100644 --- a/src/scripts/db/import-venues.js +++ b/src/scripts/db/import-venues.js @@ -1,182 +1,182 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { venueSchema } = require('../../models/venue'); - -const oldVenueSchema = require('./old-schemas/venue'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldVenue = oldDb.model('venues', oldVenueSchema); - - let totalOldVenues; - try { - totalOldVenues = await OldVenue.find({ - lngLat: { $exists: true }, - place_id: { $exists: true, $ne: '' }, - types: { $ne: [] } - }).count(); - } catch (error) { - console.log('Old venues failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old venues: ${totalOldVenues}`); - - console.time('createVenues'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldVenues; - try { - oldVenues = await OldVenue.find({ - lngLat: { $exists: true }, - place_id: { $exists: true, $ne: '' }, - types: { $ne: [] } - }) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old venues failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const Venue = db.model('Venue', venueSchema); - - const createVenues = []; - for (let oldVenue of oldVenues) { - const addressOne = oldVenue.addr1; - const addressTwo = oldVenue.addr2 ? ` ${oldVenue.addr2}` : ''; - const city = oldVenue.city ? `, ${oldVenue.city}` : ''; - const state = oldVenue.state ? `, ${oldVenue.state}` : ''; - const address = `${addressOne}${addressTwo}${city}${state}`; - - const bathroomScore = - oldVenue.bathroom >= 1 ? oldVenue.bathroom : undefined; - const entryScore = oldVenue.entry >= 1 ? oldVenue.entry : undefined; - - let longitude; - if (oldVenue.lngLat[1] >= -180 && oldVenue.lngLat[1] <= 180) { - longitude = oldVenue.lngLat[1]; - } - let latitude; - if (oldVenue.lngLat[0] >= -90 && oldVenue.lngLat[0] <= 90) { - latitude = oldVenue.lngLat[0]; - } else { - longitude = oldVenue.lngLat[0]; - latitude = oldVenue.lngLat[1]; - } - - const venueData = { - _id: oldVenue.id, - address: oldVenue.addr1 ? address : '', - allowsGuideDog: { yes: oldVenue.guidedog }, - bathroomReviews: oldVenue.b_reviews, - bathroomScore, - createdAt: oldVenue.created_at, - entryReviews: oldVenue.e_reviews, - entryScore, - hasParking: { yes: oldVenue.parking }, - hasRamp: { yes: oldVenue.ramp }, - hasSecondEntry: { yes: oldVenue.secondentrance }, - hasWellLit: { yes: oldVenue.welllit }, - isQuiet: { yes: oldVenue.quiet }, - isSpacious: { yes: oldVenue.spacious }, - location: { coordinates: [longitude, latitude] }, - name: oldVenue.name, - placeId: oldVenue.place_id, - reviews: oldVenue.reviewdata, - steps: { - zero: oldVenue.steps_0, - one: oldVenue.steps_1, - two: oldVenue.steps_2, - moreThanTwo: oldVenue.steps_3 - }, - types: oldVenue.types, - updatedAt: oldVenue.updated_at - }; - - createVenues.push(Venue.create(venueData)); - } - - try { - await Promise.all(createVenues); - } catch (error) { - console.log( - `Venues failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldVenues.length; - console.log(i); - } while (i < totalOldVenues); - - console.timeEnd('createVenues'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { venueSchema } = require('../../models/venue'); + +const oldVenueSchema = require('./old-schemas/venue'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldVenue = oldDb.model('venues', oldVenueSchema); + + let totalOldVenues; + try { + totalOldVenues = await OldVenue.find({ + lngLat: { $exists: true }, + place_id: { $exists: true, $ne: '' }, + types: { $ne: [] } + }).count(); + } catch (error) { + console.log('Old venues failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old venues: ${totalOldVenues}`); + + console.time('createVenues'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldVenues; + try { + oldVenues = await OldVenue.find({ + lngLat: { $exists: true }, + place_id: { $exists: true, $ne: '' }, + types: { $ne: [] } + }) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old venues failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const Venue = db.model('Venue', venueSchema); + + const createVenues = []; + for (let oldVenue of oldVenues) { + const addressOne = oldVenue.addr1; + const addressTwo = oldVenue.addr2 ? ` ${oldVenue.addr2}` : ''; + const city = oldVenue.city ? `, ${oldVenue.city}` : ''; + const state = oldVenue.state ? `, ${oldVenue.state}` : ''; + const address = `${addressOne}${addressTwo}${city}${state}`; + + const bathroomScore = + oldVenue.bathroom >= 1 ? oldVenue.bathroom : undefined; + const entryScore = oldVenue.entry >= 1 ? oldVenue.entry : undefined; + + let longitude; + if (oldVenue.lngLat[1] >= -180 && oldVenue.lngLat[1] <= 180) { + longitude = oldVenue.lngLat[1]; + } + let latitude; + if (oldVenue.lngLat[0] >= -90 && oldVenue.lngLat[0] <= 90) { + latitude = oldVenue.lngLat[0]; + } else { + longitude = oldVenue.lngLat[0]; + latitude = oldVenue.lngLat[1]; + } + + const venueData = { + _id: oldVenue.id, + address: oldVenue.addr1 ? address : '', + allowsGuideDog: { yes: oldVenue.guidedog }, + bathroomReviews: oldVenue.b_reviews, + bathroomScore, + createdAt: oldVenue.created_at, + entryReviews: oldVenue.e_reviews, + entryScore, + hasParking: { yes: oldVenue.parking }, + hasRamp: { yes: oldVenue.ramp }, + hasSecondEntry: { yes: oldVenue.secondentrance }, + hasWellLit: { yes: oldVenue.welllit }, + isQuiet: { yes: oldVenue.quiet }, + isSpacious: { yes: oldVenue.spacious }, + location: { coordinates: [longitude, latitude] }, + name: oldVenue.name, + placeId: oldVenue.place_id, + reviews: oldVenue.reviewdata, + steps: { + zero: oldVenue.steps_0, + one: oldVenue.steps_1, + two: oldVenue.steps_2, + moreThanTwo: oldVenue.steps_3 + }, + types: oldVenue.types, + updatedAt: oldVenue.updated_at + }; + + createVenues.push(Venue.create(venueData)); + } + + try { + await Promise.all(createVenues); + } catch (error) { + console.log( + `Venues failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldVenues.length; + console.log(i); + } while (i < totalOldVenues); + + console.timeEnd('createVenues'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/old-schemas/event.js b/src/scripts/db/old-schemas/event.js index cd99ce5..370e451 100644 --- a/src/scripts/db/old-schemas/event.js +++ b/src/scripts/db/old-schemas/event.js @@ -1,83 +1,83 @@ -const mongoose = require('mongoose'); - -const Schema = mongoose.Schema; -const ObjectId = Schema.ObjectId; - -const schema = new Schema({ - name: { - type: String, - required: true - }, - description: { - type: String, - required: true - }, - creator: { - type: ObjectId, - ref: 'users', - required: true - }, - approved: { - type: Boolean, - default: true - }, - event_start: { - type: Date, - required: true - }, - event_end: { - type: Date, - required: true - }, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - }, - location: { - type: ObjectId, - ref: 'venues' - }, - goal: Number, - mapping_goal: Number, - participant_goal: Number, - participant_limit: Number, - type: String, - image: { - type: String, - default: '/images/icon_pin_mapathon_water.png' - }, - company: { - name: String, - address: String - }, - charity: { - name: String, - email: String, - website: String - }, - teams: [ - { - type: ObjectId, - ref: 'teams' - } - ], - members: [ - { - _id: false, - user: { - type: ObjectId, - ref: 'users' - }, - team: { - type: ObjectId, - ref: 'teams' - } - } - ] -}); - -module.exports = schema; +const mongoose = require('mongoose'); + +const Schema = mongoose.Schema; +const ObjectId = Schema.ObjectId; + +const schema = new Schema({ + name: { + type: String, + required: true + }, + description: { + type: String, + required: true + }, + creator: { + type: ObjectId, + ref: 'users', + required: true + }, + approved: { + type: Boolean, + default: true + }, + event_start: { + type: Date, + required: true + }, + event_end: { + type: Date, + required: true + }, + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + }, + location: { + type: ObjectId, + ref: 'venues' + }, + goal: Number, + mapping_goal: Number, + participant_goal: Number, + participant_limit: Number, + type: String, + image: { + type: String, + default: '/images/icon_pin_mapathon_water.png' + }, + company: { + name: String, + address: String + }, + charity: { + name: String, + email: String, + website: String + }, + teams: [ + { + type: ObjectId, + ref: 'teams' + } + ], + members: [ + { + _id: false, + user: { + type: ObjectId, + ref: 'users' + }, + team: { + type: ObjectId, + ref: 'teams' + } + } + ] +}); + +module.exports = schema; diff --git a/src/scripts/db/old-schemas/photo.js b/src/scripts/db/old-schemas/photo.js index d6cf920..e416234 100644 --- a/src/scripts/db/old-schemas/photo.js +++ b/src/scripts/db/old-schemas/photo.js @@ -1,37 +1,37 @@ -const mongoose = require('mongoose'); - -const reviewSchema = new mongoose.Schema({ - review_id: { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'reviews' - }, - venue_id: { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'venues' - }, - user_id: { - type: mongoose.Schema.ObjectId, - index: true - }, - flag: Number, - flaggers: [ - { - type: mongoose.Schema.ObjectId, - index: true - } - ], - s3_id: String, - url: String, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - } -}); - -module.exports = reviewSchema; +const mongoose = require('mongoose'); + +const reviewSchema = new mongoose.Schema({ + review_id: { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'reviews' + }, + venue_id: { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'venues' + }, + user_id: { + type: mongoose.Schema.ObjectId, + index: true + }, + flag: Number, + flaggers: [ + { + type: mongoose.Schema.ObjectId, + index: true + } + ], + s3_id: String, + url: String, + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + } +}); + +module.exports = reviewSchema; diff --git a/src/scripts/db/old-schemas/review.js b/src/scripts/db/old-schemas/review.js index 23ba9a9..2e9e45a 100644 --- a/src/scripts/db/old-schemas/review.js +++ b/src/scripts/db/old-schemas/review.js @@ -1,81 +1,81 @@ -const mongoose = require('mongoose'); - -const reviewSchema = new mongoose.Schema({ - venue_id: { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'venues' - }, - user_id: { - type: mongoose.Schema.ObjectId, - index: true - }, - team: { - type: mongoose.Schema.ObjectId, - ref: 'teams' - }, - event: { - type: mongoose.Schema.ObjectId, - ref: 'events' - }, - entry: Number, - bathroom: Number, - spacious: { - type: Boolean, - default: false - }, - quiet: { - type: Boolean, - default: false - }, - parking: { - type: Boolean, - default: false - }, - ramp: { - type: Boolean, - default: false - }, - secondentrance: { - type: Boolean, - default: false - }, - guidedog: { - type: Boolean, - default: false - }, - welllit: { - type: Boolean, - default: false - }, - comment: String, - username: String, - abuse: Number, - flag: Number, - flaggers: [ - { - type: mongoose.Schema.ObjectId, - index: true - } - ], - deleted: Boolean, - steps: Number, - votes: Number, - images: [ - { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'photos' - } - ], - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - } -}); - -module.exports = reviewSchema; +const mongoose = require('mongoose'); + +const reviewSchema = new mongoose.Schema({ + venue_id: { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'venues' + }, + user_id: { + type: mongoose.Schema.ObjectId, + index: true + }, + team: { + type: mongoose.Schema.ObjectId, + ref: 'teams' + }, + event: { + type: mongoose.Schema.ObjectId, + ref: 'events' + }, + entry: Number, + bathroom: Number, + spacious: { + type: Boolean, + default: false + }, + quiet: { + type: Boolean, + default: false + }, + parking: { + type: Boolean, + default: false + }, + ramp: { + type: Boolean, + default: false + }, + secondentrance: { + type: Boolean, + default: false + }, + guidedog: { + type: Boolean, + default: false + }, + welllit: { + type: Boolean, + default: false + }, + comment: String, + username: String, + abuse: Number, + flag: Number, + flaggers: [ + { + type: mongoose.Schema.ObjectId, + index: true + } + ], + deleted: Boolean, + steps: Number, + votes: Number, + images: [ + { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'photos' + } + ], + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + } +}); + +module.exports = reviewSchema; diff --git a/src/scripts/db/old-schemas/team.js b/src/scripts/db/old-schemas/team.js index be70c88..85581c3 100644 --- a/src/scripts/db/old-schemas/team.js +++ b/src/scripts/db/old-schemas/team.js @@ -1,49 +1,49 @@ -const mongoose = require('mongoose'); - -const venueSchema = new mongoose.Schema({ - name: String, - goal: Number, - corporation: String, - description: String, - password: String, - image: { - type: String, - default: '/images/icon_team.png' - }, - creator: { - type: mongoose.Schema.ObjectId, - ref: 'users' - }, - events: [ - { - type: mongoose.Schema.ObjectId, - ref: 'events' - } - ], - updated_at: { - type: Date, - default: Date.now - }, - created_at: { - type: Date, - default: Date.now - }, - members: [ - { - type: mongoose.Schema.ObjectId, - ref: 'users' - } - ], - invites: [ - { - type: mongoose.Schema.ObjectId, - ref: 'invites' - } - ], - approved: { - type: Boolean, - default: true - } -}); - -module.exports = venueSchema; +const mongoose = require('mongoose'); + +const venueSchema = new mongoose.Schema({ + name: String, + goal: Number, + corporation: String, + description: String, + password: String, + image: { + type: String, + default: '/images/icon_team.png' + }, + creator: { + type: mongoose.Schema.ObjectId, + ref: 'users' + }, + events: [ + { + type: mongoose.Schema.ObjectId, + ref: 'events' + } + ], + updated_at: { + type: Date, + default: Date.now + }, + created_at: { + type: Date, + default: Date.now + }, + members: [ + { + type: mongoose.Schema.ObjectId, + ref: 'users' + } + ], + invites: [ + { + type: mongoose.Schema.ObjectId, + ref: 'invites' + } + ], + approved: { + type: Boolean, + default: true + } +}); + +module.exports = venueSchema; diff --git a/src/scripts/db/old-schemas/user.js b/src/scripts/db/old-schemas/user.js index 311e828..46664c3 100644 --- a/src/scripts/db/old-schemas/user.js +++ b/src/scripts/db/old-schemas/user.js @@ -1,125 +1,125 @@ -const mongoose = require('mongoose'); - -const userSchema = new mongoose.Schema({ - schema_version: Number, - name: { - first: { - type: String, - required: true - }, - last: { - type: String, - required: true - } - }, - fullName: String, - type: String, - description: String, - showEmail: { - type: Boolean, - default: true - }, - showPhone: { - type: Boolean, - default: true - }, - image: { - type: String, - default: '/images/icon_guy.png' - }, - company: { - name: String, - address: String - }, - email: { - type: String, - unique: true, - required: true - }, - phone: { - type: String - }, - location: { - type: String - }, - zip: { - type: String - }, - gender: { - type: String, - default: '' - }, - disabilitytype: { - type: String, - default: '' - }, - newsletter: { - type: Boolean, - default: true - }, - isactive: { - type: Boolean, - default: false - }, - isadmin: { - type: Boolean, - default: false - }, - salt: { - type: String - }, - hash: { - type: String - }, - token: { - type: String, - default: false - }, - activatedAt: { - type: Date - }, - createdAt: { - type: Date, - default: Date.now - }, - updatedAt: { - type: Date, - default: Date.now - }, - events: [ - { - type: mongoose.Schema.ObjectId, - ref: 'events' - } - ], - images: [ - { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'photos' - } - ], - teams: [ - { - type: mongoose.Schema.ObjectId, - ref: 'teams' - } - ], - reset: { - createdAt: Date, - link: mongoose.Schema.ObjectId - }, - foursquareId: String, - facebookAuth: String, - foursquareVerified: { - type: Boolean, - default: false - }, - facebookVerified: { - type: Boolean, - default: false - }, - username: String -}); - -module.exports = userSchema; +const mongoose = require('mongoose'); + +const userSchema = new mongoose.Schema({ + schema_version: Number, + name: { + first: { + type: String, + required: true + }, + last: { + type: String, + required: true + } + }, + fullName: String, + type: String, + description: String, + showEmail: { + type: Boolean, + default: true + }, + showPhone: { + type: Boolean, + default: true + }, + image: { + type: String, + default: '/images/icon_guy.png' + }, + company: { + name: String, + address: String + }, + email: { + type: String, + unique: true, + required: true + }, + phone: { + type: String + }, + location: { + type: String + }, + zip: { + type: String + }, + gender: { + type: String, + default: '' + }, + disabilitytype: { + type: String, + default: '' + }, + newsletter: { + type: Boolean, + default: true + }, + isactive: { + type: Boolean, + default: false + }, + isadmin: { + type: Boolean, + default: false + }, + salt: { + type: String + }, + hash: { + type: String + }, + token: { + type: String, + default: false + }, + activatedAt: { + type: Date + }, + createdAt: { + type: Date, + default: Date.now + }, + updatedAt: { + type: Date, + default: Date.now + }, + events: [ + { + type: mongoose.Schema.ObjectId, + ref: 'events' + } + ], + images: [ + { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'photos' + } + ], + teams: [ + { + type: mongoose.Schema.ObjectId, + ref: 'teams' + } + ], + reset: { + createdAt: Date, + link: mongoose.Schema.ObjectId + }, + foursquareId: String, + facebookAuth: String, + foursquareVerified: { + type: Boolean, + default: false + }, + facebookVerified: { + type: Boolean, + default: false + }, + username: String +}); + +module.exports = userSchema; diff --git a/src/scripts/db/old-schemas/venue.js b/src/scripts/db/old-schemas/venue.js index 490278f..fe44826 100644 --- a/src/scripts/db/old-schemas/venue.js +++ b/src/scripts/db/old-schemas/venue.js @@ -1,119 +1,119 @@ -const mongoose = require('mongoose'); - -const venueSchema = new mongoose.Schema({ - schema_version: Number, - google_id: { - type: String, - index: true - }, - google_ref: String, - place_id: { - type: String, - index: true - }, - name: String, - addr1: String, - addr2: String, - city: String, - state: String, - ph: String, - url: String, - types: Array, - ll: Array, - lngLat: { - type: Array, - index: '2d' - }, - google_rating: { - type: Number, - default: 0 - }, - google_url: String, - entry: { - type: Number, - default: 0 - }, - e_reviews: { - type: Number, - default: 0 - }, - bathroom: { - type: Number, - default: 0 - }, - b_reviews: { - type: Number, - default: 0 - }, - welllit: { - type: Number, - default: 0 - }, - spacious: { - type: Number, - default: 0 - }, - quiet: { - type: Number, - default: 0 - }, - parking: { - type: Number, - default: 0 - }, - ramp: { - type: Number, - default: 0 - }, - secondentrance: { - type: Number, - default: 0 - }, - guidedog: { - type: Number, - default: 0 - }, - steps: { - type: Number, - default: -1 - }, - steps_0: { - type: Number, - default: 0 - }, - steps_1: { - type: Number, - default: 0 - }, - steps_2: { - type: Number, - default: 0 - }, - steps_3: { - type: Number, - default: 0 - }, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - }, - reviewdata: [ - { - type: mongoose.Schema.ObjectId, - ref: 'reviews' - } - ], - images: [ - { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'photos' - } - ] -}); - -module.exports = venueSchema; +const mongoose = require('mongoose'); + +const venueSchema = new mongoose.Schema({ + schema_version: Number, + google_id: { + type: String, + index: true + }, + google_ref: String, + place_id: { + type: String, + index: true + }, + name: String, + addr1: String, + addr2: String, + city: String, + state: String, + ph: String, + url: String, + types: Array, + ll: Array, + lngLat: { + type: Array, + index: '2d' + }, + google_rating: { + type: Number, + default: 0 + }, + google_url: String, + entry: { + type: Number, + default: 0 + }, + e_reviews: { + type: Number, + default: 0 + }, + bathroom: { + type: Number, + default: 0 + }, + b_reviews: { + type: Number, + default: 0 + }, + welllit: { + type: Number, + default: 0 + }, + spacious: { + type: Number, + default: 0 + }, + quiet: { + type: Number, + default: 0 + }, + parking: { + type: Number, + default: 0 + }, + ramp: { + type: Number, + default: 0 + }, + secondentrance: { + type: Number, + default: 0 + }, + guidedog: { + type: Number, + default: 0 + }, + steps: { + type: Number, + default: -1 + }, + steps_0: { + type: Number, + default: 0 + }, + steps_1: { + type: Number, + default: 0 + }, + steps_2: { + type: Number, + default: 0 + }, + steps_3: { + type: Number, + default: 0 + }, + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + }, + reviewdata: [ + { + type: mongoose.Schema.ObjectId, + ref: 'reviews' + } + ], + images: [ + { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'photos' + } + ] +}); + +module.exports = venueSchema; diff --git a/src/scripts/db/update-events-locations.js b/src/scripts/db/update-events-locations.js index 57ff40b..ead1a7f 100644 --- a/src/scripts/db/update-events-locations.js +++ b/src/scripts/db/update-events-locations.js @@ -1,150 +1,150 @@ -const axios = require('axios'); -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); -const { venueSchema } = require('../../models/venue'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db) { - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const Event = db.model('Event', eventSchema); - const Venue = db.model('Venue', venueSchema); - - let totalEvents; - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - - console.log(`Total events: ${totalEvents}`); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let events; - try { - events = await Event.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Events failed to be found'); - console.log(error); - await closeConnections(db); - } - - console.log(`${events.length} events found`); - - const getVenues = events.map(e => Venue.findOne({ _id: e.venue })); - let venues; - try { - venues = await Promise.all(getVenues); - } catch (err) { - console.log('Venues failed to be found'); - console.log(err); - await closeConnections(db); - } - - console.log(`${venues.length} venues found`); - - const getPlaces = venues.map(v => { - if (v) { - return axios.get( - `https://maps.googleapis.com/maps/api/place/details/json?placeid=${ - v.placeId - }&key=${process.env.PLACES_API_KEY}` - ); - } - }); - let places; - try { - places = await Promise.all(getPlaces); - } catch (err) { - console.log('Places failed to be found'); - console.log(err); - await closeConnections(db); - } - - console.log(`${places.length} places found`); - - const updateEvents = []; - const removeEvents = []; - places.map((p, i) => { - if ((p && p.data && p.data.result) || venues[i]) { - const place = p && p.data && p.data.result ? p.data.result : undefined; - const event = events[i]; - event.address = place ? place.formatted_address : venues[i].address; - event.location.coordinates = place - ? [place.geometry.location.lng, place.geometry.location.lat] - : venues[i].location.coordinates; - updateEvents.push(event.save()); - } else { - const event = events[i]; - removeEvents.push(event.remove()); - } - }); - try { - await Promise.all([...updateEvents, ...removeEvents]); - } catch (err) { - console.log( - `Events failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db); - } - - console.log('Events updated'); - - page = page + 1; - i = i + events.length; - console.log(i); - - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - } while (i < totalEvents); - - await closeConnections(db); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const axios = require('axios'); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { eventSchema } = require('../../models/event'); +const { venueSchema } = require('../../models/venue'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db) { + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const Event = db.model('Event', eventSchema); + const Venue = db.model('Venue', venueSchema); + + let totalEvents; + try { + totalEvents = await Event.count(); + } catch (error) { + console.log('Events failed to be count'); + console.log(error); + await closeConnections(db); + } + + console.log(`Total events: ${totalEvents}`); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let events; + try { + events = await Event.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Events failed to be found'); + console.log(error); + await closeConnections(db); + } + + console.log(`${events.length} events found`); + + const getVenues = events.map((e) => Venue.findOne({ _id: e.venue })); + let venues; + try { + venues = await Promise.all(getVenues); + } catch (err) { + console.log('Venues failed to be found'); + console.log(err); + await closeConnections(db); + } + + console.log(`${venues.length} venues found`); + + const getPlaces = venues.map((v) => { + if (v) { + return axios.get( + `https://maps.googleapis.com/maps/api/place/details/json?placeid=${ + v.placeId + }&key=${process.env.PLACES_API_KEY}` + ); + } + }); + let places; + try { + places = await Promise.all(getPlaces); + } catch (err) { + console.log('Places failed to be found'); + console.log(err); + await closeConnections(db); + } + + console.log(`${places.length} places found`); + + const updateEvents = []; + const removeEvents = []; + places.map((p, i) => { + if ((p && p.data && p.data.result) || venues[i]) { + const place = p && p.data && p.data.result ? p.data.result : undefined; + const event = events[i]; + event.address = place ? place.formatted_address : venues[i].address; + event.location.coordinates = place + ? [place.geometry.location.lng, place.geometry.location.lat] + : venues[i].location.coordinates; + updateEvents.push(event.save()); + } else { + const event = events[i]; + removeEvents.push(event.remove()); + } + }); + try { + await Promise.all([...updateEvents, ...removeEvents]); + } catch (err) { + console.log( + `Events failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db); + } + + console.log('Events updated'); + + page = page + 1; + i = i + events.length; + console.log(i); + + try { + totalEvents = await Event.count(); + } catch (error) { + console.log('Events failed to be count'); + console.log(error); + await closeConnections(db); + } + } while (i < totalEvents); + + await closeConnections(db); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/update-events-posters.js b/src/scripts/db/update-events-posters.js index 8159465..03c2df0 100644 --- a/src/scripts/db/update-events-posters.js +++ b/src/scripts/db/update-events-posters.js @@ -1,160 +1,160 @@ -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); - -mongoose.Promise = global.Promise; - -const s3 = new aws.S3(); - -async function closeConnections(db) { - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const Event = db.model('Event', eventSchema); - - let totalEvents; - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - - console.log(`Total events: ${totalEvents}`); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let events; - try { - events = await Event.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Teams failed to be found'); - console.log(error); - await closeConnections(db); - } - - const updateEvents = []; - const uploadEventsPosters = []; - for (let event of events) { - if (event.poster && !event.poster.includes('icon_guy')) { - let posterImage; - try { - posterImage = await jimp.read(encodeURI(event.poster)); - } catch (err) { - console.log('Event poster image failed to be read'); - console.log(err); - await closeConnections(db); - } - - if (posterImage) { - const posterExtension = posterImage.getExtension(); - const posterFileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${posterExtension}`; - - if ( - posterExtension === 'png' || - posterExtension === 'jpeg' || - posterExtension === 'jpg' || - posterExtension === 'bmp' - ) { - const posterMIME = posterImage.getMIME(); - if (posterMIME) { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/${posterFileName}`; - posterImage - .cover(400, 400) - .quality(85) - .getBuffer(posterMIME, async (err, posterBuffer) => { - if (err) { - console.log('Event poster buffer failed to be read'); - console.log(err); - await closeConnections(db); - } - - uploadEventsPosters.push( - s3 - .putObject({ - ACL: 'public-read', - Body: posterBuffer, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: posterImage.getMIME(), - Key: `events/posters/${posterFileName}` - }) - .promise() - ); - }); - } else { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`; - } - } - } - } else { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`; - } - updateEvents.push(event.save()); - } - - try { - await Promise.all([...updateEvents, ...uploadEventsPosters]); - } catch (err) { - console.log( - `Events failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db); - } - - page = page + 1; - i = i + events.length; - console.log(i); - } while (i < totalEvents); - - await closeConnections(db); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); + +require('dotenv').config(); + +const { eventSchema } = require('../../models/event'); + +mongoose.Promise = global.Promise; + +const s3 = new aws.S3(); + +async function closeConnections(db) { + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const Event = db.model('Event', eventSchema); + + let totalEvents; + try { + totalEvents = await Event.count(); + } catch (error) { + console.log('Events failed to be count'); + console.log(error); + await closeConnections(db); + } + + console.log(`Total events: ${totalEvents}`); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let events; + try { + events = await Event.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Teams failed to be found'); + console.log(error); + await closeConnections(db); + } + + const updateEvents = []; + const uploadEventsPosters = []; + for (let event of events) { + if (event.poster && !event.poster.includes('icon_guy')) { + let posterImage; + try { + posterImage = await jimp.read(encodeURI(event.poster)); + } catch (err) { + console.log('Event poster image failed to be read'); + console.log(err); + await closeConnections(db); + } + + if (posterImage) { + const posterExtension = posterImage.getExtension(); + const posterFileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${posterExtension}`; + + if ( + posterExtension === 'png' || + posterExtension === 'jpeg' || + posterExtension === 'jpg' || + posterExtension === 'bmp' + ) { + const posterMIME = posterImage.getMIME(); + if (posterMIME) { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/${posterFileName}`; + posterImage + .cover(400, 400) + .quality(85) + .getBuffer(posterMIME, async (err, posterBuffer) => { + if (err) { + console.log('Event poster buffer failed to be read'); + console.log(err); + await closeConnections(db); + } + + uploadEventsPosters.push( + s3 + .putObject({ + ACL: 'public-read', + Body: posterBuffer, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: posterImage.getMIME(), + Key: `events/posters/${posterFileName}` + }) + .promise() + ); + }); + } else { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`; + } + } + } + } else { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`; + } + updateEvents.push(event.save()); + } + + try { + await Promise.all([...updateEvents, ...uploadEventsPosters]); + } catch (err) { + console.log( + `Events failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db); + } + + page = page + 1; + i = i + events.length; + console.log(i); + } while (i < totalEvents); + + await closeConnections(db); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/update-events-reviews.js b/src/scripts/db/update-events-reviews.js index b2e2afe..bf9950e 100644 --- a/src/scripts/db/update-events-reviews.js +++ b/src/scripts/db/update-events-reviews.js @@ -1,104 +1,104 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); -const { reviewSchema } = require('../../models/review'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db) { - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const Event = db.model('Event', eventSchema); - const Review = db.model('Review', reviewSchema); - - let totalEvents; - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - - console.log(`Total events: ${totalEvents}`); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let events; - try { - events = await Event.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Teams failed to be found'); - console.log(error); - await closeConnections(db); - } - - const updateEvents = []; - for (let event of events) { - let eventReviews; - try { - eventReviews = await Review.find({ event: event.id }).count(); - } catch (err) { - console.log('Event reviews failed to be count'); - console.log(err); - await closeConnections(db); - } - - event.reviewsAmount = eventReviews; - updateEvents.push(event.save()); - } - - try { - await Promise.all(updateEvents); - } catch (err) { - console.log( - `Events failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db); - } - - page = page + 1; - i = i + events.length; - console.log(i); - } while (i < totalEvents); - - await closeConnections(db); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { eventSchema } = require('../../models/event'); +const { reviewSchema } = require('../../models/review'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db) { + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const Event = db.model('Event', eventSchema); + const Review = db.model('Review', reviewSchema); + + let totalEvents; + try { + totalEvents = await Event.count(); + } catch (error) { + console.log('Events failed to be count'); + console.log(error); + await closeConnections(db); + } + + console.log(`Total events: ${totalEvents}`); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let events; + try { + events = await Event.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Teams failed to be found'); + console.log(error); + await closeConnections(db); + } + + const updateEvents = []; + for (let event of events) { + let eventReviews; + try { + eventReviews = await Review.find({ event: event.id }).count(); + } catch (err) { + console.log('Event reviews failed to be count'); + console.log(err); + await closeConnections(db); + } + + event.reviewsAmount = eventReviews; + updateEvents.push(event.save()); + } + + try { + await Promise.all(updateEvents); + } catch (err) { + console.log( + `Events failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db); + } + + page = page + 1; + i = i + events.length; + console.log(i); + } while (i < totalEvents); + + await closeConnections(db); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/update-users-avatars.js b/src/scripts/db/update-users-avatars.js index 59e21c5..5df6f61 100644 --- a/src/scripts/db/update-users-avatars.js +++ b/src/scripts/db/update-users-avatars.js @@ -1,206 +1,206 @@ -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); - -require('dotenv').config(); - -const { userSchema } = require('../../models/user'); - -const oldUserSchema = require('./old-schemas/user'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldUser = oldDb.model('users', oldUserSchema); - - let totalOldUsers; - try { - totalOldUsers = await OldUser.count(); - } catch (error) { - console.log('Old users failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old users: ${totalOldUsers}`); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldUsers; - try { - oldUsers = await OldUser.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old users failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const User = db.model('User', userSchema); - - const getUsersImages = []; - const usersToUpdate = []; - for (let oldUser of oldUsers) { - if (oldUser.isactive) { - if (oldUser.image && !oldUser.image.includes('icon_guy.png')) { - getUsersImages.push(jimp.read(encodeURI(oldUser.image))); - usersToUpdate.push(oldUser.id); - } - } - } - - if (getUsersImages.length > 0) { - let usersImages; - try { - usersImages = await Promise.all(getUsersImages); - } catch (error) { - console.log( - `Old users images failed to be found.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - const usersAvatars = []; - for (let i = 0; i < usersImages.length; i++) { - usersImages[i].cover(400, 400).quality(60); - usersImages[i].getBuffer( - usersImages[i].getMIME(), - (error, bufferImage) => { - if (error) { - console.log(error); - } - - const extension = usersImages[i].getExtension(); - if ( - extension === 'png' || - extension === 'jpeg' || - extension === 'jpg' || - extension === 'bmp' - ) { - usersAvatars.push({ - body: bufferImage, - extension: extension, - mime: usersImages[i].getMIME(), - userId: usersToUpdate[i] - }); - } - } - ); - } - - const s3 = new aws.S3(); - const uploadUsersAvatars = []; - const updateUsersAvatars = []; - for (let userAvatar of usersAvatars) { - let fileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${userAvatar.extension}`; - - uploadUsersAvatars.push( - s3 - .putObject({ - ACL: 'public-read', - Body: userAvatar.body, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: userAvatar.mime, - Key: `users/avatars/${fileName}` - }) - .promise() - ); - - let avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/users/avatars/${fileName}`; - - updateUsersAvatars.push( - User.update({ _id: userAvatar.userId }, { $set: { avatar } }) - ); - } - - try { - await Promise.all([...uploadUsersAvatars, ...updateUsersAvatars]); - } catch (error) { - console.log( - `Users images failed to be uploaded or updated.\nData: ${JSON.stringify( - { - page, - i - } - )}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - } - - page = page + 1; - i = i + oldUsers.length; - console.log(i); - } while (i < totalOldUsers); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); - -process.on('SIGINT', () => db.close()); +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); + +require('dotenv').config(); + +const { userSchema } = require('../../models/user'); + +const oldUserSchema = require('./old-schemas/user'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldUser = oldDb.model('users', oldUserSchema); + + let totalOldUsers; + try { + totalOldUsers = await OldUser.count(); + } catch (error) { + console.log('Old users failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old users: ${totalOldUsers}`); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldUsers; + try { + oldUsers = await OldUser.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old users failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const User = db.model('User', userSchema); + + const getUsersImages = []; + const usersToUpdate = []; + for (let oldUser of oldUsers) { + if (oldUser.isactive) { + if (oldUser.image && !oldUser.image.includes('icon_guy.png')) { + getUsersImages.push(jimp.read(encodeURI(oldUser.image))); + usersToUpdate.push(oldUser.id); + } + } + } + + if (getUsersImages.length > 0) { + let usersImages; + try { + usersImages = await Promise.all(getUsersImages); + } catch (error) { + console.log( + `Old users images failed to be found.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + const usersAvatars = []; + for (let i = 0; i < usersImages.length; i++) { + usersImages[i].cover(400, 400).quality(60); + usersImages[i].getBuffer( + usersImages[i].getMIME(), + (error, bufferImage) => { + if (error) { + console.log(error); + } + + const extension = usersImages[i].getExtension(); + if ( + extension === 'png' || + extension === 'jpeg' || + extension === 'jpg' || + extension === 'bmp' + ) { + usersAvatars.push({ + body: bufferImage, + extension: extension, + mime: usersImages[i].getMIME(), + userId: usersToUpdate[i] + }); + } + } + ); + } + + const s3 = new aws.S3(); + const uploadUsersAvatars = []; + const updateUsersAvatars = []; + for (let userAvatar of usersAvatars) { + let fileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${userAvatar.extension}`; + + uploadUsersAvatars.push( + s3 + .putObject({ + ACL: 'public-read', + Body: userAvatar.body, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: userAvatar.mime, + Key: `users/avatars/${fileName}` + }) + .promise() + ); + + let avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/users/avatars/${fileName}`; + + updateUsersAvatars.push( + User.update({ _id: userAvatar.userId }, { $set: { avatar } }) + ); + } + + try { + await Promise.all([...uploadUsersAvatars, ...updateUsersAvatars]); + } catch (error) { + console.log( + `Users images failed to be uploaded or updated.\nData: ${JSON.stringify( + { + page, + i + } + )}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + } + + page = page + 1; + i = i + oldUsers.length; + console.log(i); + } while (i < totalOldUsers); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); + +process.on('SIGINT', () => db.close());