diff --git a/.eslintrc.json b/.eslintrc.json index f24799a5..3e685a0d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,10 +1,10 @@ { "extends": ["eslint:recommended", "plugin:prettier/recommended", "plugin:jsdoc/recommended"], - "plugins": ["prettier", "jsdoc"], + "plugins": ["prettier", "jsdoc", "jest"], "env": { "browser": true, "es6": true, - "mocha": true, + "jest/globals": true, "node": true }, "globals": { diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index c09454eb..87635902 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,3 +1,7 @@ +Hello and thank you for opening an issue. + +**Please make sure that you have read the following lines before submitting your Issue:** + ## I'm not sure if this is a bug If you're not sure if it's a real bug or if it's just you, please open a topic on the forum: [https://forum.magicmirror.builders/category/15/bug-hunt](https://forum.magicmirror.builders/category/15/bug-hunt) diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 00000000..3f76e9b5 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,6 @@ +coverage: + status: + project: + default: + # advanced settings + informational: true diff --git a/.github/workflows/codecov-test-suites.yml b/.github/workflows/codecov-test-suites.yml index 0d98e3a0..1a6d4e0e 100644 --- a/.github/workflows/codecov-test-suites.yml +++ b/.github/workflows/codecov-test-suites.yml @@ -11,6 +11,7 @@ on: jobs: run-and-upload-coverage-report: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@v2 - run: | diff --git a/.github/workflows/enforce-changelog.yml b/.github/workflows/enforce-changelog.yml index 67a95a48..d4a5a994 100644 --- a/.github/workflows/enforce-changelog.yml +++ b/.github/workflows/enforce-changelog.yml @@ -9,6 +9,7 @@ on: jobs: check: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v2 - uses: dangoslen/changelog-enforcer@v1.6.1 diff --git a/.github/workflows/node-ci.js.yml b/.github/workflows/node-ci.js.yml index 7f6f23b1..b5dd7aee 100644 --- a/.github/workflows/node-ci.js.yml +++ b/.github/workflows/node-ci.js.yml @@ -12,9 +12,10 @@ on: jobs: test: runs-on: ubuntu-latest + timeout-minutes: 30 strategy: matrix: - node-version: [10.x, 12.x, 14.x] + node-version: [12.x, 14.x, 16.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} @@ -28,5 +29,5 @@ jobs: npm run test:prettier npm run test:js npm run test:css - npm run test:e2e npm run test:unit + npm run test:e2e diff --git a/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 00000000..31354ec1 --- /dev/null +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000..3199e8e0 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npm run lint:staged diff --git a/.prettierignore b/.prettierignore index b829fa7c..eeaa248d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,5 +1,8 @@ -package-lock.json -/config/**/* -/vendor/**/* +/config +/coverage +/vendor !/vendor/vendor.js -.github/**/* +.github +.nyc_output +package-lock.json +*.ts diff --git a/README.md b/README.md index 0d75c7ef..8a243f89 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ CodeCov Status License Tests -

**MagicMirror²** is an open source modular smart mirror platform. With a growing list of installable modules, the **MagicMirror²** allows you to convert your hallway or bathroom mirror into your personal assistant. **MagicMirror²** is built by the creator of [the original MagicMirror](https://michaelteeuw.nl/tagged/magicmirror) with the incredible help of a [growing community of contributors](https://github.com/MichMich/MagicMirror/graphs/contributors). @@ -23,6 +22,7 @@ For the full documentation including **[installation instructions](https://docs. - Website: [https://magicmirror.builders](https://magicmirror.builders) - Documentation: [https://docs.magicmirror.builders](https://docs.magicmirror.builders) - Forum: [https://forum.magicmirror.builders](https://forum.magicmirror.builders) + - Technical discussions: https://forum.magicmirror.builders/category/11/core-system - Discord: [https://discord.gg/J5BAtvx](https://discord.gg/J5BAtvx) - Blog: [https://michaelteeuw.nl/tagged/magicmirror](https://michaelteeuw.nl/tagged/magicmirror) - Donations: [https://magicmirror.builders/#donate](https://magicmirror.builders/#donate) diff --git a/clientonly/index.js b/clientonly/index.js index 3564eef8..1a0a7970 100644 --- a/clientonly/index.js +++ b/clientonly/index.js @@ -2,7 +2,7 @@ // Use separate scope to prevent global scope pollution (function () { - var config = {}; + const config = {}; /** * Helper function to get server address/hostname from either the commandline or env @@ -17,8 +17,8 @@ * @returns {string} the value of the parameter */ function getCommandLineParameter(key, defaultValue = undefined) { - var index = process.argv.indexOf(`--${key}`); - var value = index > -1 ? process.argv[index + 1] : undefined; + const index = process.argv.indexOf(`--${key}`); + const value = index > -1 ? process.argv[index + 1] : undefined; return value !== undefined ? String(value) : defaultValue; } @@ -43,7 +43,7 @@ // Select http or https module, depending on requested url const lib = url.startsWith("https") ? require("https") : require("http"); const request = lib.get(url, (response) => { - var configData = ""; + let configData = ""; // Gather incoming data response.on("data", function (chunk) { @@ -79,15 +79,15 @@ getServerAddress(); (config.address && config.port) || fail(); - var prefix = config.tls ? "https://" : "http://"; + const prefix = config.tls ? "https://" : "http://"; // Only start the client if a non-local server was provided if (["localhost", "127.0.0.1", "::1", "::ffff:127.0.0.1", undefined].indexOf(config.address) === -1) { getServerConfig(`${prefix}${config.address}:${config.port}/config/`) .then(function (configReturn) { // Pass along the server config via an environment variable - var env = Object.create(process.env); - var options = { env: env }; + const env = Object.create(process.env); + const options = { env: env }; configReturn.address = config.address; configReturn.port = config.port; configReturn.tls = config.tls; diff --git a/config/config.js.sample b/config/config.js.sample index e17ae195..d02c74ef 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -4,11 +4,10 @@ * MIT Licensed. * * For more information on how you can configure this file - * See https://github.com/MichMich/MagicMirror#configuration - * + * see https://docs.magicmirror.builders/getting-started/configuration.html#general + * and https://docs.magicmirror.builders/modules/configuration.html */ - -var config = { +let config = { address: "localhost", // Address to listen on, can be: // - "localhost", "127.0.0.1", "::1" to listen on loopback interface // - another specific IPv4/6 to listen on a specific interface diff --git a/css/custom.css.sample b/css/custom.css.sample new file mode 100644 index 00000000..ac5b5e2e --- /dev/null +++ b/css/custom.css.sample @@ -0,0 +1,31 @@ +/* Magic Mirror Custom CSS Sample + * + * Change color and fonts here. + * + * Beware that properties cannot be unitless, so for example write '--gap-body: 0px;' instead of just '--gap-body: 0;' + * + * MIT Licensed. + */ + +/* Uncomment and adjust accordingly if you want to import another font from the google-fonts-api: */ +/* @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@100;300;400;700&display=swap'); */ + +:root { + --color-text: #999; + --color-text-dimmed: #666; + --color-text-bright: #fff; + --color-background: black; + + --font-primary: "Roboto Condensed"; + --font-secondary: "Roboto"; + + --font-size: 20px; + --font-size-small: 0.75rem; + + --gap-body-top: 60px; + --gap-body-right: 60px; + --gap-body-bottom: 60px; + --gap-body-left: 60px; + + --gap-modules: 30px; +} diff --git a/css/main.css b/css/main.css index 16c281be..a36ca5e4 100644 --- a/css/main.css +++ b/css/main.css @@ -1,8 +1,29 @@ +:root { + --color-text: #999; + --color-text-dimmed: #666; + --color-text-bright: #fff; + --color-background: #000; + + --font-primary: "Roboto Condensed"; + --font-secondary: "Roboto"; + + --font-size: 20px; + --font-size-small: 0.75rem; + + --gap-body-top: 60px; + --gap-body-right: 60px; + --gap-body-bottom: 60px; + --gap-body-left: 60px; + + --gap-modules: 30px; +} + html { cursor: none; overflow: hidden; - background: #000; + background: var(--color-background); user-select: none; + font-size: var(--font-size); } ::-webkit-scrollbar { @@ -10,16 +31,15 @@ html { } body { - margin: 60px; + margin: var(--gap-body-top) var(--gap-body-right) var(--gap-body-bottom) var(--gap-body-left); position: absolute; - height: calc(100% - 120px); - width: calc(100% - 120px); - background: #000; - color: #aaa; - font-family: "Roboto Condensed", sans-serif; + height: calc(100% - var(--gap-body-top) - var(--gap-body-bottom)); + width: calc(100% - var(--gap-body-right) - var(--gap-body-left)); + background: var(--color-background); + color: var(--color-text); + font-family: var(--font-primary), sans-serif; font-weight: 400; - font-size: 2em; - line-height: 1.5em; + line-height: 1.5; -webkit-font-smoothing: antialiased; } @@ -28,60 +48,60 @@ body { */ .dimmed { - color: #666; + color: var(--color-text-dimmed); } .normal { - color: #999; + color: var(--color-text); } .bright { - color: #fff; + color: var(--color-text-bright); } .xsmall { - font-size: 15px; - line-height: 20px; + font-size: var(--font-size-small); + line-height: 1.275; } .small { - font-size: 20px; - line-height: 25px; + font-size: 1rem; + line-height: 1.25; } .medium { - font-size: 30px; - line-height: 35px; + font-size: 1.5rem; + line-height: 1.225; } .large { - font-size: 65px; - line-height: 65px; + font-size: 3.25rem; + line-height: 1; } .xlarge { - font-size: 75px; - line-height: 75px; + font-size: 3.75rem; + line-height: 1; letter-spacing: -3px; } .thin { - font-family: Roboto, sans-serif; + font-family: var(--font-secondary), sans-serif; font-weight: 100; } .light { - font-family: "Roboto Condensed", sans-serif; + font-family: var(--font-primary), sans-serif; font-weight: 300; } .regular { - font-family: "Roboto Condensed", sans-serif; + font-family: var(--font-primary), sans-serif; font-weight: 400; } .bold { - font-family: "Roboto Condensed", sans-serif; + font-family: var(--font-primary), sans-serif; font-weight: 700; } @@ -95,14 +115,14 @@ body { header { text-transform: uppercase; - font-size: 15px; - font-family: "Roboto Condensed", Arial, Helvetica, sans-serif; + font-size: var(--font-size-small); + font-family: var(--font-primary), Arial, Helvetica, sans-serif; font-weight: 400; - border-bottom: 1px solid #666; + border-bottom: 1px solid var(--color-text-dimmed); line-height: 15px; padding-bottom: 5px; margin-bottom: 10px; - color: #999; + color: var(--color-text); } sup { @@ -115,11 +135,11 @@ sup { */ .module { - margin-bottom: 30px; + margin-bottom: var(--gap-modules); } .region.bottom .module { - margin-top: 30px; + margin-top: var(--gap-modules); margin-bottom: 0; } @@ -143,10 +163,10 @@ sup { .region.fullscreen { position: absolute; - top: -60px; - left: -60px; - right: -60px; - bottom: -60px; + top: calc(-1 * var(--gap-body-top)); + left: calc(-1 * var(--gap-body-left)); + right: calc(-1 * var(--gap-body-right)); + bottom: calc(-1 * var(--gap-body-bottom)); pointer-events: none; } @@ -163,18 +183,6 @@ sup { top: 0; } -.region.top .container { - margin-bottom: 25px; -} - -.region.bottom .container { - margin-top: 25px; -} - -.region.top .container:empty { - margin-bottom: 0; -} - .region.top.center, .region.bottom.center { left: 50%; @@ -191,10 +199,6 @@ sup { bottom: 0; } -.region.bottom .container:empty { - margin-top: 0; -} - .region.bottom.right, .region.bottom.center, .region.bottom.left { diff --git a/fonts/package-lock.json b/fonts/package-lock.json index 960e793a..2f944edf 100644 --- a/fonts/package-lock.json +++ b/fonts/package-lock.json @@ -1,12 +1,12 @@ { - "name": "magicmirror-fonts", - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "roboto-fontface": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", - "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==" - } - } + "name": "magicmirror-fonts", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "roboto-fontface": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", + "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==" + } + } } diff --git a/index.html b/index.html index 5a46bb72..c9f2239c 100644 --- a/index.html +++ b/index.html @@ -1,55 +1,57 @@ - - MagicMirror² - - + + MagicMirror² + + - - - - + + + + - - - - + + + + - - - -
-
-
-
-
-
-
-
-
-

-
-
-
-
-
-
-
- - - - - - - - - - - - - - - + + + +
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + diff --git a/js/app.js b/js/app.js index e5156b19..6315370b 100644 --- a/js/app.js +++ b/js/app.js @@ -180,7 +180,6 @@ function App() { * * @param {string} a Version number a. * @param {string} b Version number b. - * * @returns {number} A positive number if a is larger than b, a negative * number if a is smaller and 0 if they are the same */ diff --git a/js/check_config.js b/js/check_config.js index 01cd08e2..60b4cdf3 100644 --- a/js/check_config.js +++ b/js/check_config.js @@ -52,7 +52,13 @@ function checkConfigFile() { // I'm not sure if all ever is utf-8 const configFile = fs.readFileSync(configFileName, "utf-8"); - const errors = linter.verify(configFile); + // Explicitly tell linter that he might encounter es6 syntax ("let config = {...}") + const errors = linter.verify(configFile, { + env: { + es6: true + } + }); + if (errors.length === 0) { Log.info(Utils.colors.pass("Your configuration file doesn't contain syntax errors :)")); } else { diff --git a/js/class.js b/js/class.js index 9c46a894..b25ced0a 100644 --- a/js/class.js +++ b/js/class.js @@ -84,7 +84,6 @@ * Define the clone method for later use. Helper Method. * * @param {object} obj Object to be cloned - * * @returns {object} the cloned object */ function cloneObject(obj) { diff --git a/js/defaults.js b/js/defaults.js index 8a890bc5..0173a594 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -6,12 +6,12 @@ * By Michael Teeuw https://michaelteeuw.nl * MIT Licensed. */ -var address = "localhost"; -var port = 8080; +const address = "localhost"; +let port = 8080; if (typeof mmPort !== "undefined") { port = mmPort; } -var defaults = { +const defaults = { address: address, port: port, basePath: "/", diff --git a/js/electron.js b/js/electron.js index 6c2f44a7..a834f7ab 100644 --- a/js/electron.js +++ b/js/electron.js @@ -63,6 +63,11 @@ function createWindow() { // Open the DevTools if run with "npm start dev" if (process.argv.includes("dev")) { + if (process.env.JEST_WORKER_ID !== undefined) { + // if we are running with jest + var devtools = new BrowserWindow(electronOptions); + mainWindow.webContents.setDevToolsWebContents(devtools.webContents); + } mainWindow.webContents.openDevTools(); } diff --git a/js/loader.js b/js/loader.js index f290ff44..e3c88be4 100644 --- a/js/loader.js +++ b/js/loader.js @@ -6,24 +6,24 @@ * By Michael Teeuw https://michaelteeuw.nl * MIT Licensed. */ -var Loader = (function () { +const Loader = (function () { /* Create helper variables */ - var loadedModuleFiles = []; - var loadedFiles = []; - var moduleObjects = []; + const loadedModuleFiles = []; + const loadedFiles = []; + const moduleObjects = []; /* Private Methods */ /** * Loops thru all modules and requests load for every module. */ - var loadModules = function () { - var moduleData = getModuleData(); + const loadModules = function () { + let moduleData = getModuleData(); - var loadNextModule = function () { + const loadNextModule = function () { if (moduleData.length > 0) { - var nextModule = moduleData[0]; + const nextModule = moduleData[0]; loadModule(nextModule, function () { moduleData = moduleData.slice(1); loadNextModule(); @@ -46,9 +46,8 @@ var Loader = (function () { /** * Loops thru all modules and requests start for every module. */ - var startModules = function () { - for (var m in moduleObjects) { - var module = moduleObjects[m]; + const startModules = function () { + for (const module of moduleObjects) { module.start(); } @@ -56,7 +55,7 @@ var Loader = (function () { MM.modulesStarted(moduleObjects); // Starting modules also hides any modules that have requested to be initially hidden - for (let thisModule of moduleObjects) { + for (const thisModule of moduleObjects) { if (thisModule.data.hiddenOnStartup) { Log.info("Initially hiding " + thisModule.name); thisModule.hide(); @@ -69,7 +68,7 @@ var Loader = (function () { * * @returns {object[]} module data as configured in config */ - var getAllModules = function () { + const getAllModules = function () { return config.modules; }; @@ -78,29 +77,28 @@ var Loader = (function () { * * @returns {object[]} Module information. */ - var getModuleData = function () { - var modules = getAllModules(); - var moduleFiles = []; + const getModuleData = function () { + const modules = getAllModules(); + const moduleFiles = []; - for (var m in modules) { - var moduleData = modules[m]; - var module = moduleData.module; + modules.forEach(function (moduleData, index) { + const module = moduleData.module; - var elements = module.split("/"); - var moduleName = elements[elements.length - 1]; - var moduleFolder = config.paths.modules + "/" + module; + const elements = module.split("/"); + const moduleName = elements[elements.length - 1]; + let moduleFolder = config.paths.modules + "/" + module; if (defaultModules.indexOf(moduleName) !== -1) { moduleFolder = config.paths.modules + "/default/" + module; } if (moduleData.disabled === true) { - continue; + return; } moduleFiles.push({ - index: m, - identifier: "module_" + m + "_" + module, + index: index, + identifier: "module_" + index + "_" + module, name: moduleName, path: moduleFolder + "/", file: moduleName + ".js", @@ -111,7 +109,7 @@ var Loader = (function () { config: moduleData.config, classes: typeof moduleData.classes !== "undefined" ? moduleData.classes + " " + module : module }); - } + }); return moduleFiles; }; @@ -122,11 +120,11 @@ var Loader = (function () { * @param {object} module Information about the module we want to load. * @param {Function} callback Function called when done. */ - var loadModule = function (module, callback) { - var url = module.path + module.file; + const loadModule = function (module, callback) { + const url = module.path + module.file; - var afterLoad = function () { - var moduleObject = Module.create(module.name); + const afterLoad = function () { + const moduleObject = Module.create(module.name); if (moduleObject) { bootstrapModule(module, moduleObject, function () { callback(); @@ -153,7 +151,7 @@ var Loader = (function () { * @param {Module} mObj Modules instance. * @param {Function} callback Function called when done. */ - var bootstrapModule = function (module, mObj, callback) { + const bootstrapModule = function (module, mObj, callback) { Log.info("Bootstrapping module: " + module.name); mObj.setData(module); @@ -177,13 +175,14 @@ var Loader = (function () { * @param {string} fileName Path of the file we want to load. * @param {Function} callback Function called when done. */ - var loadFile = function (fileName, callback) { - var extension = fileName.slice((Math.max(0, fileName.lastIndexOf(".")) || Infinity) + 1); + const loadFile = function (fileName, callback) { + const extension = fileName.slice((Math.max(0, fileName.lastIndexOf(".")) || Infinity) + 1); + let script, stylesheet; switch (extension.toLowerCase()) { case "js": Log.log("Load script: " + fileName); - var script = document.createElement("script"); + script = document.createElement("script"); script.type = "text/javascript"; script.src = fileName; script.onload = function () { @@ -202,7 +201,7 @@ var Loader = (function () { break; case "css": Log.log("Load stylesheet: " + fileName); - var stylesheet = document.createElement("link"); + stylesheet = document.createElement("link"); stylesheet.rel = "stylesheet"; stylesheet.type = "text/css"; stylesheet.href = fileName; diff --git a/js/main.js b/js/main.js index 6f5d9484..bc128194 100644 --- a/js/main.js +++ b/js/main.js @@ -6,25 +6,25 @@ * By Michael Teeuw https://michaelteeuw.nl * MIT Licensed. */ -var MM = (function () { - var modules = []; +const MM = (function () { + let modules = []; /* Private Methods */ /** * Create dom objects for all modules that are configured for a specific position. */ - var createDomObjects = function () { - var domCreationPromises = []; + const createDomObjects = function () { + const domCreationPromises = []; modules.forEach(function (module) { if (typeof module.data.position !== "string") { return; } - var wrapper = selectWrapper(module.data.position); + const wrapper = selectWrapper(module.data.position); - var dom = document.createElement("div"); + const dom = document.createElement("div"); dom.id = module.identifier; dom.className = module.name; @@ -35,7 +35,7 @@ var MM = (function () { dom.opacity = 0; wrapper.appendChild(dom); - var moduleHeader = document.createElement("header"); + const moduleHeader = document.createElement("header"); moduleHeader.innerHTML = module.getHeader(); moduleHeader.className = "module-header"; dom.appendChild(moduleHeader); @@ -46,11 +46,11 @@ var MM = (function () { moduleHeader.style.display = "block;"; } - var moduleContent = document.createElement("div"); + const moduleContent = document.createElement("div"); moduleContent.className = "module-content"; dom.appendChild(moduleContent); - var domCreationPromise = updateDom(module, 0); + const domCreationPromise = updateDom(module, 0); domCreationPromises.push(domCreationPromise); domCreationPromise .then(function () { @@ -70,14 +70,13 @@ var MM = (function () { * Select the wrapper dom object for a specific position. * * @param {string} position The name of the position. - * * @returns {HTMLElement} the wrapper element */ - var selectWrapper = function (position) { - var classes = position.replace("_", " "); - var parentWrapper = document.getElementsByClassName(classes); + const selectWrapper = function (position) { + const classes = position.replace("_", " "); + const parentWrapper = document.getElementsByClassName(classes); if (parentWrapper.length > 0) { - var wrapper = parentWrapper[0].getElementsByClassName("container"); + const wrapper = parentWrapper[0].getElementsByClassName("container"); if (wrapper.length > 0) { return wrapper[0]; } @@ -92,9 +91,9 @@ var MM = (function () { * @param {Module} sender The module that sent the notification. * @param {Module} [sendTo] The (optional) module to send the notification to. */ - var sendNotification = function (notification, payload, sender, sendTo) { - for (var m in modules) { - var module = modules[m]; + const sendNotification = function (notification, payload, sender, sendTo) { + for (const m in modules) { + const module = modules[m]; if (module !== sender && (!sendTo || module === sendTo)) { module.notificationReceived(notification, payload, sender); } @@ -106,13 +105,12 @@ var MM = (function () { * * @param {Module} module The module that needs an update. * @param {number} [speed] The (optional) number of microseconds for the animation. - * * @returns {Promise} Resolved when the dom is fully updated. */ - var updateDom = function (module, speed) { + const updateDom = function (module, speed) { return new Promise(function (resolve) { - var newContentPromise = module.getDom(); - var newHeader = module.getHeader(); + const newHeader = module.getHeader(); + let newContentPromise = module.getDom(); if (!(newContentPromise instanceof Promise)) { // convert to a promise if not already one to avoid if/else's everywhere @@ -121,7 +119,7 @@ var MM = (function () { newContentPromise .then(function (newContent) { - var updatePromise = updateDomWithContent(module, speed, newHeader, newContent); + const updatePromise = updateDomWithContent(module, speed, newHeader, newContent); updatePromise.then(resolve).catch(Log.error); }) @@ -136,10 +134,9 @@ var MM = (function () { * @param {number} [speed] The (optional) number of microseconds for the animation. * @param {string} newHeader The new header that is generated. * @param {HTMLElement} newContent The new content that is generated. - * * @returns {Promise} Resolved when the module dom has been updated. */ - var updateDomWithContent = function (module, speed, newHeader, newContent) { + const updateDomWithContent = function (module, speed, newHeader, newContent) { return new Promise(function (resolve) { if (module.hidden || !speed) { updateModuleContent(module, newHeader, newContent); @@ -174,26 +171,25 @@ var MM = (function () { * @param {Module} module The module to check. * @param {string} newHeader The new header that is generated. * @param {HTMLElement} newContent The new content that is generated. - * * @returns {boolean} True if the module need an update, false otherwise */ - var moduleNeedsUpdate = function (module, newHeader, newContent) { - var moduleWrapper = document.getElementById(module.identifier); + const moduleNeedsUpdate = function (module, newHeader, newContent) { + const moduleWrapper = document.getElementById(module.identifier); if (moduleWrapper === null) { return false; } - var contentWrapper = moduleWrapper.getElementsByClassName("module-content"); - var headerWrapper = moduleWrapper.getElementsByClassName("module-header"); + const contentWrapper = moduleWrapper.getElementsByClassName("module-content"); + const headerWrapper = moduleWrapper.getElementsByClassName("module-header"); - var headerNeedsUpdate = false; - var contentNeedsUpdate = false; + let headerNeedsUpdate = false; + let contentNeedsUpdate; if (headerWrapper.length > 0) { headerNeedsUpdate = newHeader !== headerWrapper[0].innerHTML; } - var tempContentWrapper = document.createElement("div"); + const tempContentWrapper = document.createElement("div"); tempContentWrapper.appendChild(newContent); contentNeedsUpdate = tempContentWrapper.innerHTML !== contentWrapper[0].innerHTML; @@ -207,13 +203,13 @@ var MM = (function () { * @param {string} newHeader The new header that is generated. * @param {HTMLElement} newContent The new content that is generated. */ - var updateModuleContent = function (module, newHeader, newContent) { - var moduleWrapper = document.getElementById(module.identifier); + const updateModuleContent = function (module, newHeader, newContent) { + const moduleWrapper = document.getElementById(module.identifier); if (moduleWrapper === null) { return; } - var headerWrapper = moduleWrapper.getElementsByClassName("module-header"); - var contentWrapper = moduleWrapper.getElementsByClassName("module-content"); + const headerWrapper = moduleWrapper.getElementsByClassName("module-header"); + const contentWrapper = moduleWrapper.getElementsByClassName("module-content"); contentWrapper[0].innerHTML = ""; contentWrapper[0].appendChild(newContent); @@ -234,7 +230,7 @@ var MM = (function () { * @param {Function} callback Called when the animation is done. * @param {object} [options] Optional settings for the hide method. */ - var hideModule = function (module, speed, callback, options) { + const hideModule = function (module, speed, callback, options) { options = options || {}; // set lockString if set in options. @@ -245,7 +241,7 @@ var MM = (function () { } } - var moduleWrapper = document.getElementById(module.identifier); + const moduleWrapper = document.getElementById(module.identifier); if (moduleWrapper !== null) { moduleWrapper.style.transition = "opacity " + speed / 1000 + "s"; moduleWrapper.style.opacity = 0; @@ -280,12 +276,12 @@ var MM = (function () { * @param {Function} callback Called when the animation is done. * @param {object} [options] Optional settings for the show method. */ - var showModule = function (module, speed, callback, options) { + const showModule = function (module, speed, callback, options) { options = options || {}; // remove lockString if set in options. if (options.lockString) { - var index = module.lockStrings.indexOf(options.lockString); + const index = module.lockStrings.indexOf(options.lockString); if (index !== -1) { module.lockStrings.splice(index, 1); } @@ -309,7 +305,7 @@ var MM = (function () { module.lockStrings = []; } - var moduleWrapper = document.getElementById(module.identifier); + const moduleWrapper = document.getElementById(module.identifier); if (moduleWrapper !== null) { moduleWrapper.style.transition = "opacity " + speed / 1000 + "s"; // Restore the position. See hideModule() for more info. @@ -318,7 +314,7 @@ var MM = (function () { updateWrapperStates(); // Waiting for DOM-changes done in updateWrapperStates before we can start the animation. - var dummy = moduleWrapper.parentElement.parentElement.offsetHeight; + const dummy = moduleWrapper.parentElement.parentElement.offsetHeight; moduleWrapper.style.opacity = 1; clearTimeout(module.showHideTimer); @@ -346,14 +342,14 @@ var MM = (function () { * an ugly top margin. By using this function, the top bar will be hidden if the * update notification is not visible. */ - var updateWrapperStates = function () { - var positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"]; + const updateWrapperStates = function () { + const positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"]; positions.forEach(function (position) { - var wrapper = selectWrapper(position); - var moduleWrappers = wrapper.getElementsByClassName("module"); + const wrapper = selectWrapper(position); + const moduleWrappers = wrapper.getElementsByClassName("module"); - var showWrapper = false; + let showWrapper = false; Array.prototype.forEach.call(moduleWrappers, function (moduleWrapper) { if (moduleWrapper.style.position === "" || moduleWrapper.style.position === "static") { showWrapper = true; @@ -367,7 +363,7 @@ var MM = (function () { /** * Loads the core config and combines it with the system defaults. */ - var loadConfig = function () { + const loadConfig = function () { // FIXME: Think about how to pass config around without breaking tests /* eslint-disable */ if (typeof config === "undefined") { @@ -385,15 +381,14 @@ var MM = (function () { * * @param {Module[]} modules Array of modules. */ - var setSelectionMethodsForModules = function (modules) { + const setSelectionMethodsForModules = function (modules) { /** * Filter modules with the specified classes. * * @param {string|string[]} className one or multiple classnames (array or space divided). - * * @returns {Module[]} Filtered collection of modules. */ - var withClass = function (className) { + const withClass = function (className) { return modulesByClass(className, true); }; @@ -401,10 +396,9 @@ var MM = (function () { * Filter modules without the specified classes. * * @param {string|string[]} className one or multiple classnames (array or space divided). - * * @returns {Module[]} Filtered collection of modules. */ - var exceptWithClass = function (className) { + const exceptWithClass = function (className) { return modulesByClass(className, false); }; @@ -413,20 +407,18 @@ var MM = (function () { * * @param {string|string[]} className one or multiple classnames (array or space divided). * @param {boolean} include if the filter should include or exclude the modules with the specific classes. - * * @returns {Module[]} Filtered collection of modules. */ - var modulesByClass = function (className, include) { - var searchClasses = className; + const modulesByClass = function (className, include) { + let searchClasses = className; if (typeof className === "string") { searchClasses = className.split(" "); } - var newModules = modules.filter(function (module) { - var classes = module.data.classes.toLowerCase().split(" "); + const newModules = modules.filter(function (module) { + const classes = module.data.classes.toLowerCase().split(" "); - for (var c in searchClasses) { - var searchClass = searchClasses[c]; + for (const searchClass of searchClasses) { if (classes.indexOf(searchClass.toLowerCase()) !== -1) { return include; } @@ -445,8 +437,8 @@ var MM = (function () { * @param {object} module The module instance to remove from the collection. * @returns {Module[]} Filtered collection of modules. */ - var exceptModule = function (module) { - var newModules = modules.filter(function (mod) { + const exceptModule = function (module) { + const newModules = modules.filter(function (mod) { return mod.identifier !== module.identifier; }); @@ -459,7 +451,7 @@ var MM = (function () { * * @param {Function} callback The function to execute with the module as an argument. */ - var enumerate = function (callback) { + const enumerate = function (callback) { modules.map(function (module) { callback(module); }); @@ -604,11 +596,11 @@ if (typeof Object.assign !== "function") { if (target === undefined || target === null) { throw new TypeError("Cannot convert undefined or null to object"); } - var output = Object(target); - for (var index = 1; index < arguments.length; index++) { - var source = arguments[index]; + const output = Object(target); + for (let index = 1; index < arguments.length; index++) { + const source = arguments[index]; if (source !== undefined && source !== null) { - for (var nextKey in source) { + for (const nextKey in source) { if (source.hasOwnProperty(nextKey)) { output[nextKey] = source[nextKey]; } diff --git a/js/module.js b/js/module.js index 042b674b..b754e197 100644 --- a/js/module.js +++ b/js/module.js @@ -6,7 +6,6 @@ * * By Michael Teeuw https://michaelteeuw.nl * MIT Licensed. - * */ var Module = Class.extend({ /********************************************************* @@ -82,16 +81,15 @@ var Module = Class.extend({ * @returns {HTMLElement|Promise} The dom or a promise with the dom to display. */ getDom: function () { - var self = this; - return new Promise(function (resolve) { - var div = document.createElement("div"); - var template = self.getTemplate(); - var templateData = self.getTemplateData(); + return new Promise((resolve) => { + const div = document.createElement("div"); + const template = this.getTemplate(); + const templateData = this.getTemplateData(); // Check to see if we need to render a template string or a file. if (/^.*((\.html)|(\.njk))$/.test(template)) { // the template is a filename - self.nunjucksEnvironment().render(template, templateData, function (err, res) { + this.nunjucksEnvironment().render(template, templateData, function (err, res) { if (err) { Log.error(err); } @@ -102,7 +100,7 @@ var Module = Class.extend({ }); } else { // the template is a template string. - div.innerHTML = self.nunjucksEnvironment().renderString(template, templateData); + div.innerHTML = this.nunjucksEnvironment().renderString(template, templateData); resolve(div); } @@ -168,15 +166,13 @@ var Module = Class.extend({ return this._nunjucksEnvironment; } - var self = this; - this._nunjucksEnvironment = new nunjucks.Environment(new nunjucks.WebLoader(this.file(""), { async: true }), { trimBlocks: true, lstripBlocks: true }); - this._nunjucksEnvironment.addFilter("translate", function (str, variables) { - return nunjucks.runtime.markSafe(self.translate(str, variables)); + this._nunjucksEnvironment.addFilter("translate", (str, variables) => { + return nunjucks.runtime.markSafe(this.translate(str, variables)); }); return this._nunjucksEnvironment; @@ -192,14 +188,14 @@ var Module = Class.extend({ Log.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload); }, - /* + /** * Called when the module is hidden. */ suspend: function () { Log.log(this.name + " is suspended."); }, - /* + /** * Called when the module is shown. */ resume: function () { @@ -213,7 +209,7 @@ var Module = Class.extend({ /** * Set the module data. * - * @param {Module} data The module data + * @param {object} data The module data */ setData: function (data) { this.data = data; @@ -245,9 +241,8 @@ var Module = Class.extend({ this._socket = new MMSocket(this.name); } - var self = this; - this._socket.setNotificationCallback(function (notification, payload) { - self.socketNotificationReceived(notification, payload); + this._socket.setNotificationCallback((notification, payload) => { + this.socketNotificationReceived(notification, payload); }); return this._socket; @@ -288,13 +283,12 @@ var Module = Class.extend({ * @param {Function} callback Function called when done. */ loadDependencies: function (funcName, callback) { - var self = this; - var dependencies = this[funcName](); + let dependencies = this[funcName](); - var loadNextDependency = function () { + const loadNextDependency = () => { if (dependencies.length > 0) { - var nextDependency = dependencies[0]; - Loader.loadFile(nextDependency, self, function () { + const nextDependency = dependencies[0]; + Loader.loadFile(nextDependency, this, () => { dependencies = dependencies.slice(1); loadNextDependency(); }); @@ -400,12 +394,11 @@ var Module = Class.extend({ callback = callback || function () {}; options = options || {}; - var self = this; MM.hideModule( - self, + this, speed, - function () { - self.suspend(); + () => { + this.suspend(); callback(); }, options @@ -464,9 +457,9 @@ var Module = Class.extend({ * @returns {object} the merged config */ function configMerge(result) { - var stack = Array.prototype.slice.call(arguments, 1); - var item; - var key; + const stack = Array.prototype.slice.call(arguments, 1); + let item, key; + while (stack.length) { item = stack.shift(); for (key in item) { @@ -494,11 +487,11 @@ Module.create = function (name) { return; } - var moduleDefinition = Module.definitions[name]; - var clonedDefinition = cloneObject(moduleDefinition); + const moduleDefinition = Module.definitions[name]; + const clonedDefinition = cloneObject(moduleDefinition); // Note that we clone the definition. Otherwise the objects are shared, which gives problems. - var ModuleClass = Module.extend(clonedDefinition); + const ModuleClass = Module.extend(clonedDefinition); return new ModuleClass(); }; @@ -526,14 +519,13 @@ Module.register = function (name, moduleDefinition) { * number if a is smaller and 0 if they are the same */ function cmpVersions(a, b) { - var i, diff; - var regExStrip0 = /(\.0+)+$/; - var segmentsA = a.replace(regExStrip0, "").split("."); - var segmentsB = b.replace(regExStrip0, "").split("."); - var l = Math.min(segmentsA.length, segmentsB.length); + const regExStrip0 = /(\.0+)+$/; + const segmentsA = a.replace(regExStrip0, "").split("."); + const segmentsB = b.replace(regExStrip0, "").split("."); + const l = Math.min(segmentsA.length, segmentsB.length); - for (i = 0; i < l; i++) { - diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10); + for (let i = 0; i < l; i++) { + let diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10); if (diff) { return diff; } diff --git a/js/node_helper.js b/js/node_helper.js index 81d2d9d5..86ad3aa4 100644 --- a/js/node_helper.js +++ b/js/node_helper.js @@ -113,6 +113,32 @@ const NodeHelper = Class.extend({ } }); +NodeHelper.checkFetchStatus = function (response) { + // response.status >= 200 && response.status < 300 + if (response.ok) { + return response; + } else { + throw Error(response.statusText); + } +}; + +/** + * Look at the specified error and return an appropriate error type, that + * can be translated to a detailed error message + * + * @param {Error} error the error from fetching something + * @returns {string} the string of the detailed error message in the translations + */ +NodeHelper.checkFetchError = function (error) { + let error_type = "MODULE_ERROR_UNSPECIFIED"; + if (error.code === "EAI_AGAIN") { + error_type = "MODULE_ERROR_NO_CONNECTION"; + } else if (error.message === "Unauthorized") { + error_type = "MODULE_ERROR_UNAUTHORIZED"; + } + return error_type; +}; + NodeHelper.create = function (moduleDefinition) { return NodeHelper.extend(moduleDefinition); }; diff --git a/js/socketclient.js b/js/socketclient.js index 2a50083f..acb8cfdc 100644 --- a/js/socketclient.js +++ b/js/socketclient.js @@ -6,49 +6,48 @@ * By Michael Teeuw https://michaelteeuw.nl * MIT Licensed. */ -var MMSocket = function (moduleName) { - var self = this; - +const MMSocket = function (moduleName) { if (typeof moduleName !== "string") { throw new Error("Please set the module name for the MMSocket."); } - self.moduleName = moduleName; + this.moduleName = moduleName; // Private Methods - var base = "/"; + let base = "/"; if (typeof config !== "undefined" && typeof config.basePath !== "undefined") { base = config.basePath; } - self.socket = io("/" + self.moduleName, { + this.socket = io("/" + this.moduleName, { path: base + "socket.io" }); - var notificationCallback = function () {}; - var onevent = self.socket.onevent; - self.socket.onevent = function (packet) { - var args = packet.data || []; - onevent.call(this, packet); // original call + let notificationCallback = function () {}; + + const onevent = this.socket.onevent; + this.socket.onevent = (packet) => { + const args = packet.data || []; + onevent.call(this.socket, packet); // original call packet.data = ["*"].concat(args); - onevent.call(this, packet); // additional call to catch-all + onevent.call(this.socket, packet); // additional call to catch-all }; // register catch all. - self.socket.on("*", function (notification, payload) { + this.socket.on("*", (notification, payload) => { if (notification !== "*") { notificationCallback(notification, payload); } }); // Public Methods - this.setNotificationCallback = function (callback) { + this.setNotificationCallback = (callback) => { notificationCallback = callback; }; - this.sendNotification = function (notification, payload) { + this.sendNotification = (notification, payload) => { if (typeof payload === "undefined") { payload = {}; } - self.socket.emit(notification, payload); + this.socket.emit(notification, payload); }; }; diff --git a/modules/default/alert/alert.js b/modules/default/alert/alert.js index 8d175b39..2e471ac1 100644 --- a/modules/default/alert/alert.js +++ b/modules/default/alert/alert.js @@ -79,7 +79,7 @@ Module.register("alert", { //If module already has an open alert close it if (this.alerts[sender.name]) { - this.hide_alert(sender); + this.hide_alert(sender, false); } //Display title and message only if they are provided in notification parameters @@ -114,10 +114,10 @@ Module.register("alert", { }, params.timer); } }, - hide_alert: function (sender) { + hide_alert: function (sender, close = true) { //Dismiss alert and remove from this.alerts if (this.alerts[sender.name]) { - this.alerts[sender.name].dismiss(); + this.alerts[sender.name].dismiss(close); this.alerts[sender.name] = null; //Remove overlay const overlay = document.getElementById("overlay"); diff --git a/modules/default/alert/notificationFx.css b/modules/default/alert/notificationFx.css index 0782d464..39faacf7 100644 --- a/modules/default/alert/notificationFx.css +++ b/modules/default/alert/notificationFx.css @@ -6,7 +6,6 @@ line-height: 1.4; margin-bottom: 10px; z-index: 1; - color: black; font-size: 70%; position: relative; display: table; @@ -15,17 +14,17 @@ border-width: 1px; border-radius: 5px; border-style: solid; - border-color: #666; + border-color: var(--color-text-dimmed); } .ns-alert { border-style: solid; - border-color: #fff; + border-color: var(--color-text-bright); padding: 17px; line-height: 1.4; margin-bottom: 10px; z-index: 3; - color: white; + color: var(--color-text-bright); font-size: 70%; position: fixed; text-align: center; diff --git a/modules/default/alert/notificationFx.js b/modules/default/alert/notificationFx.js index 89034420..317fa75a 100644 --- a/modules/default/alert/notificationFx.js +++ b/modules/default/alert/notificationFx.js @@ -122,8 +122,10 @@ /** * Dismiss the notification + * + * @param {boolean} [close] call the onClose callback at the end */ - NotificationFx.prototype.dismiss = function () { + NotificationFx.prototype.dismiss = function (close = true) { this.active = false; clearTimeout(this.dismissttl); this.ntf.classList.remove("ns-show"); @@ -131,7 +133,7 @@ this.ntf.classList.add("ns-hide"); // callback - this.options.onClose(); + if (close) this.options.onClose(); }, 25); // after animation ends remove ntf from the DOM diff --git a/modules/default/calendar/calendar.css b/modules/default/calendar/calendar.css index 65908a70..f04d6838 100644 --- a/modules/default/calendar/calendar.css +++ b/modules/default/calendar/calendar.css @@ -1,13 +1,14 @@ .calendar .symbol { + display: flex; + flex-direction: row; + justify-content: flex-end; padding-left: 0; padding-right: 10px; - font-size: 80%; - vertical-align: top; + font-size: var(--font-size-small); } .calendar .symbol span { - display: inline-block; - transform: translate(0, 2px); + padding-top: 4px; } .calendar .title { diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index 292ceab1..7525e3a8 100755 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -84,7 +84,7 @@ Module.register("calendar", { // Override start method. start: function () { - Log.log("Starting module: " + this.name); + Log.info("Starting module: " + this.name); // Set locale. moment.updateLocale(config.language, this.getLocaleSpecification(config.timeFormat)); @@ -140,17 +140,17 @@ Module.register("calendar", { if (notification === "CALENDAR_EVENTS") { if (this.hasCalendarURL(payload.url)) { this.calendarData[payload.url] = payload.events; + this.error = null; this.loaded = true; if (this.config.broadcastEvents) { this.broadcastEvents(); } } - } else if (notification === "FETCH_ERROR") { - Log.error("Calendar Error. Could not fetch calendar: " + payload.url); + } else if (notification === "CALENDAR_ERROR") { + let error_message = this.translate(payload.error_type); + this.error = this.translate("MODULE_CONFIG_ERROR", { MODULE_NAME: this.name, ERROR: error_message }); this.loaded = true; - } else if (notification === "INCORRECT_URL") { - Log.error("Calendar Error. Incorrect url: " + payload.url); } this.updateDom(this.config.animationSpeed); @@ -168,6 +168,12 @@ Module.register("calendar", { const wrapper = document.createElement("table"); wrapper.className = this.config.tableClass; + if (this.error) { + wrapper.innerHTML = this.error; + wrapper.className = this.config.tableClass + " dimmed"; + return wrapper; + } + if (events.length === 0) { wrapper.innerHTML = this.loaded ? this.translate("EMPTY") : this.translate("LOADING"); wrapper.className = this.config.tableClass + " dimmed"; @@ -305,15 +311,14 @@ Module.register("calendar", { if (this.config.timeFormat === "dateheaders") { if (event.fullDayEvent) { titleWrapper.colSpan = "2"; - titleWrapper.align = "left"; + titleWrapper.classList.add("align-left"); } else { const timeWrapper = document.createElement("td"); - timeWrapper.className = "time light " + this.timeClassForUrl(event.url); - timeWrapper.align = "left"; + timeWrapper.className = "time light align-left " + this.timeClassForUrl(event.url); timeWrapper.style.paddingLeft = "2px"; timeWrapper.innerHTML = moment(event.startDate, "x").format("LT"); eventWrapper.appendChild(timeWrapper); - titleWrapper.align = "right"; + titleWrapper.classList.add("align-right"); } eventWrapper.appendChild(titleWrapper); @@ -366,13 +371,14 @@ Module.register("calendar", { if (event.startDate >= now) { // Use relative time if (!this.config.hideTime) { - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar()); + timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar(null, { sameElse: this.config.dateFormat })); } else { timeWrapper.innerHTML = this.capFirst( moment(event.startDate, "x").calendar(null, { sameDay: "[" + this.translate("TODAY") + "]", nextDay: "[" + this.translate("TOMORROW") + "]", - nextWeek: "dddd" + nextWeek: "dddd", + sameElse: this.config.dateFormat }) ); } diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js index 9673fa31..805e080b 100644 --- a/modules/default/calendar/calendarfetcher.js +++ b/modules/default/calendar/calendarfetcher.js @@ -6,6 +6,7 @@ */ const CalendarUtils = require("./calendarutils"); const Log = require("logger"); +const NodeHelper = require("node_helper"); const ical = require("node-ical"); const fetch = require("node-fetch"); const digest = require("digest-fetch"); @@ -52,27 +53,17 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn if (auth.method === "bearer") { headers.Authorization = "Bearer " + auth.pass; } else if (auth.method === "digest") { - fetcher = new digest(auth.user, auth.pass).fetch(url, { headers: headers, httpsAgent: httpsAgent }); + fetcher = new digest(auth.user, auth.pass).fetch(url, { headers: headers, agent: httpsAgent }); } else { headers.Authorization = "Basic " + Buffer.from(auth.user + ":" + auth.pass).toString("base64"); } } if (fetcher === null) { - fetcher = fetch(url, { headers: headers, httpsAgent: httpsAgent }); + fetcher = fetch(url, { headers: headers, agent: httpsAgent }); } fetcher - .catch((error) => { - fetchFailedCallback(this, error); - scheduleTimer(); - }) - .then((response) => { - if (response.status !== 200) { - fetchFailedCallback(this, response.statusText); - scheduleTimer(); - } - return response; - }) + .then(NodeHelper.checkFetchStatus) .then((response) => response.text()) .then((responseData) => { let data = []; @@ -87,12 +78,16 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn maximumNumberOfDays }); } catch (error) { - fetchFailedCallback(this, error.message); + fetchFailedCallback(this, error); scheduleTimer(); return; } this.broadcastEvents(); scheduleTimer(); + }) + .catch((error) => { + fetchFailedCallback(this, error); + scheduleTimer(); }); }; diff --git a/modules/default/calendar/calendarutils.js b/modules/default/calendar/calendarutils.js index 223dfb26..7f0b14b8 100644 --- a/modules/default/calendar/calendarutils.js +++ b/modules/default/calendar/calendarutils.js @@ -18,8 +18,8 @@ const CalendarUtils = { * Calculate the time correction, either dst/std or full day in cases where * utc time is day before plus offset * - * @param {object} event - * @param {Date} date + * @param {object} event the event which needs adjustement + * @param {Date} date the date on which this event happens * @returns {number} the necessary adjustment in hours */ calculateTimezoneAdjustment: function (event, date) { @@ -117,6 +117,13 @@ const CalendarUtils = { return adjustHours; }, + /** + * Filter the events from ical according to the given config + * + * @param {object} data the calendar data from ical + * @param {object} config The configuration object + * @returns {string[]} the filtered events + */ filterEvents: function (data, config) { const newEvents = []; @@ -500,8 +507,8 @@ const CalendarUtils = { /** * Lookup iana tz from windows * - * @param msTZName - * @returns {*|null} + * @param {string} msTZName the timezone name to lookup + * @returns {string|null} the iana name or null of none is found */ getIanaTZFromMS: function (msTZName) { // Get hash entry @@ -571,12 +578,13 @@ const CalendarUtils = { }, /** + * Determines if the user defined title filter should apply * - * @param title - * @param filter - * @param useRegex - * @param regexFlags - * @returns {boolean|*} + * @param {string} title the title of the event + * @param {string} filter the string to look for, can be a regex also + * @param {boolean} useRegex true if a regex should be used, otherwise it just looks for the filter as a string + * @param {string} regexFlags flags that should be applied to the regex + * @returns {boolean} True if the title should be filtered out, false otherwise */ titleFilterApplies: function (title, filter, useRegex, regexFlags) { if (useRegex) { diff --git a/modules/default/calendar/debug.js b/modules/default/calendar/debug.js index f01bcc0d..f2d3a48e 100644 --- a/modules/default/calendar/debug.js +++ b/modules/default/calendar/debug.js @@ -5,6 +5,9 @@ * By Michael Teeuw https://michaelteeuw.nl * MIT Licensed. */ +// Alias modules mentioned in package.js under _moduleAliases. +require("module-alias/register"); + const CalendarFetcher = require("./calendarfetcher.js"); const url = "https://calendar.google.com/calendar/ical/pkm1t2uedjbp0uvq1o7oj1jouo%40group.calendar.google.com/private-08ba559f89eec70dd74bbd887d0a3598/basic.ics"; // Standard test URL @@ -26,11 +29,13 @@ const fetcher = new CalendarFetcher(url, fetchInterval, [], maximumEntries, maxi fetcher.onReceive(function (fetcher) { console.log(fetcher.events()); console.log("------------------------------------------------------------"); + process.exit(0); }); fetcher.onError(function (fetcher, error) { console.log("Fetcher error:"); console.log(error); + process.exit(1); }); fetcher.startFetch(); diff --git a/modules/default/calendar/node_helper.js b/modules/default/calendar/node_helper.js index d544878b..5b1a8bad 100644 --- a/modules/default/calendar/node_helper.js +++ b/modules/default/calendar/node_helper.js @@ -40,13 +40,14 @@ module.exports = NodeHelper.create({ try { new URL(url); } catch (error) { - this.sendSocketNotification("INCORRECT_URL", { id: identifier, url: url }); + Log.error("Calendar Error. Malformed calendar url: ", url, error); + this.sendSocketNotification("CALENDAR_ERROR", { error_type: "MODULE_ERROR_MALFORMED_URL" }); return; } let fetcher; if (typeof this.fetchers[identifier + url] === "undefined") { - Log.log("Create new calendar fetcher for url: " + url + " - Interval: " + fetchInterval); + Log.log("Create new calendarfetcher for url: " + url + " - Interval: " + fetchInterval); fetcher = new CalendarFetcher(url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents, selfSignedCert); fetcher.onReceive((fetcher) => { @@ -55,16 +56,16 @@ module.exports = NodeHelper.create({ fetcher.onError((fetcher, error) => { Log.error("Calendar Error. Could not fetch calendar: ", fetcher.url(), error); - this.sendSocketNotification("FETCH_ERROR", { + let error_type = NodeHelper.checkFetchError(error); + this.sendSocketNotification("CALENDAR_ERROR", { id: identifier, - url: fetcher.url(), - error: error + error_type }); }); this.fetchers[identifier + url] = fetcher; } else { - Log.log("Use existing calendar fetcher for url: " + url); + Log.log("Use existing calendarfetcher for url: " + url); fetcher = this.fetchers[identifier + url]; fetcher.broadcastEvents(); } diff --git a/modules/default/clock/clock.js b/modules/default/clock/clock.js index 6e3d7090..fbab09a0 100644 --- a/modules/default/clock/clock.js +++ b/modules/default/clock/clock.js @@ -46,62 +46,61 @@ Module.register("clock", { Log.info("Starting module: " + this.name); // Schedule update interval. - var self = this; - self.second = moment().second(); - self.minute = moment().minute(); + this.second = moment().second(); + this.minute = moment().minute(); - //Calculate how many ms should pass until next update depending on if seconds is displayed or not - var delayCalculator = function (reducedSeconds) { - var EXTRA_DELAY = 50; //Deliberate imperceptable delay to prevent off-by-one timekeeping errors + // Calculate how many ms should pass until next update depending on if seconds is displayed or not + const delayCalculator = (reducedSeconds) => { + const EXTRA_DELAY = 50; // Deliberate imperceptible delay to prevent off-by-one timekeeping errors - if (self.config.displaySeconds) { + if (this.config.displaySeconds) { return 1000 - moment().milliseconds() + EXTRA_DELAY; } else { return (60 - reducedSeconds) * 1000 - moment().milliseconds() + EXTRA_DELAY; } }; - //A recursive timeout function instead of interval to avoid drifting - var notificationTimer = function () { - self.updateDom(); + // A recursive timeout function instead of interval to avoid drifting + const notificationTimer = () => { + this.updateDom(); - //If seconds is displayed CLOCK_SECOND-notification should be sent (but not when CLOCK_MINUTE-notification is sent) - if (self.config.displaySeconds) { - self.second = moment().second(); - if (self.second !== 0) { - self.sendNotification("CLOCK_SECOND", self.second); + // If seconds is displayed CLOCK_SECOND-notification should be sent (but not when CLOCK_MINUTE-notification is sent) + if (this.config.displaySeconds) { + this.second = moment().second(); + if (this.second !== 0) { + this.sendNotification("CLOCK_SECOND", this.second); setTimeout(notificationTimer, delayCalculator(0)); return; } } - //If minute changed or seconds isn't displayed send CLOCK_MINUTE-notification - self.minute = moment().minute(); - self.sendNotification("CLOCK_MINUTE", self.minute); + // If minute changed or seconds isn't displayed send CLOCK_MINUTE-notification + this.minute = moment().minute(); + this.sendNotification("CLOCK_MINUTE", this.minute); setTimeout(notificationTimer, delayCalculator(0)); }; - //Set the initial timeout with the amount of seconds elapsed as reducedSeconds so it will trigger when the minute changes - setTimeout(notificationTimer, delayCalculator(self.second)); + // Set the initial timeout with the amount of seconds elapsed as reducedSeconds so it will trigger when the minute changes + setTimeout(notificationTimer, delayCalculator(this.second)); // Set locale. moment.locale(config.language); }, // Override dom generator. getDom: function () { - var wrapper = document.createElement("div"); + const wrapper = document.createElement("div"); /************************************ * Create wrappers for DIGITAL clock */ - var dateWrapper = document.createElement("div"); - var timeWrapper = document.createElement("div"); - var secondsWrapper = document.createElement("sup"); - var periodWrapper = document.createElement("span"); - var sunWrapper = document.createElement("div"); - var moonWrapper = document.createElement("div"); - var weekWrapper = document.createElement("div"); + const dateWrapper = document.createElement("div"); + const timeWrapper = document.createElement("div"); + const secondsWrapper = document.createElement("sup"); + const periodWrapper = document.createElement("span"); + const sunWrapper = document.createElement("div"); + const moonWrapper = document.createElement("div"); + const weekWrapper = document.createElement("div"); // Style Wrappers dateWrapper.className = "date normal medium"; timeWrapper.className = "time bright large light"; @@ -114,14 +113,13 @@ Module.register("clock", { // The moment().format("h") method has a bug on the Raspberry Pi. // So we need to generate the timestring manually. // See issue: https://github.com/MichMich/MagicMirror/issues/181 - var timeString; - var now = moment(); - this.lastDisplayedMinute = now.minute(); + let timeString; + const now = moment(); if (this.config.timezone) { now.tz(this.config.timezone); } - var hourSymbol = "HH"; + let hourSymbol = "HH"; if (this.config.timeFormat !== 24) { hourSymbol = "h"; } @@ -160,7 +158,7 @@ Module.register("clock", { * @returns {string} The formatted time string */ function formatTime(config, time) { - var formatString = hourSymbol + ":mm"; + let formatString = hourSymbol + ":mm"; if (config.showPeriod && config.timeFormat !== 24) { formatString += config.showPeriodUpper ? "A" : "a"; } @@ -170,7 +168,7 @@ Module.register("clock", { if (this.config.showSunTimes) { const sunTimes = SunCalc.getTimes(now, this.config.lat, this.config.lon); const isVisible = now.isBetween(sunTimes.sunrise, sunTimes.sunset); - var nextEvent; + let nextEvent; if (now.isBefore(sunTimes.sunrise)) { nextEvent = sunTimes.sunrise; } else if (now.isBefore(sunTimes.sunset)) { @@ -198,7 +196,7 @@ Module.register("clock", { const moonIllumination = SunCalc.getMoonIllumination(now.toDate()); const moonTimes = SunCalc.getMoonTimes(now, this.config.lat, this.config.lon); const moonRise = moonTimes.rise; - var moonSet; + let moonSet; if (moment(moonTimes.set).isAfter(moonTimes.rise)) { moonSet = moonTimes.set; } else { @@ -224,6 +222,7 @@ Module.register("clock", { /**************************************************************** * Create wrappers for ANALOG clock, only if specified in config */ + const clockCircle = document.createElement("div"); if (this.config.displayType !== "digital") { // If it isn't 'digital', then an 'analog' clock was also requested @@ -232,12 +231,11 @@ Module.register("clock", { if (this.config.timezone) { now.tz(this.config.timezone); } - var second = now.seconds() * 6, + const second = now.seconds() * 6, minute = now.minute() * 6 + second / 60, hour = ((now.hours() % 12) / 12) * 360 + 90 + minute / 12; // Create wrappers - var clockCircle = document.createElement("div"); clockCircle.className = "clockCircle"; clockCircle.style.width = this.config.analogSize; clockCircle.style.height = this.config.analogSize; @@ -252,14 +250,14 @@ Module.register("clock", { } else if (this.config.analogFace !== "none") { clockCircle.style.border = "2px solid white"; } - var clockFace = document.createElement("div"); + const clockFace = document.createElement("div"); clockFace.className = "clockFace"; - var clockHour = document.createElement("div"); + const clockHour = document.createElement("div"); clockHour.id = "clockHour"; clockHour.style.transform = "rotate(" + hour + "deg)"; clockHour.className = "clockHour"; - var clockMinute = document.createElement("div"); + const clockMinute = document.createElement("div"); clockMinute.id = "clockMinute"; clockMinute.style.transform = "rotate(" + minute + "deg)"; clockMinute.className = "clockMinute"; @@ -269,7 +267,7 @@ Module.register("clock", { clockFace.appendChild(clockMinute); if (this.config.displaySeconds) { - var clockSecond = document.createElement("div"); + const clockSecond = document.createElement("div"); clockSecond.id = "clockSecond"; clockSecond.style.transform = "rotate(" + second + "deg)"; clockSecond.className = "clockSecond"; @@ -312,14 +310,14 @@ Module.register("clock", { } } else { // Both clocks have been configured, check position - var placement = this.config.analogPlacement; + const placement = this.config.analogPlacement; - var analogWrapper = document.createElement("div"); + const analogWrapper = document.createElement("div"); analogWrapper.id = "analog"; analogWrapper.style.cssFloat = "none"; analogWrapper.appendChild(clockCircle); - var digitalWrapper = document.createElement("div"); + const digitalWrapper = document.createElement("div"); digitalWrapper.id = "digital"; digitalWrapper.style.cssFloat = "none"; digitalWrapper.appendChild(dateWrapper); @@ -328,8 +326,8 @@ Module.register("clock", { digitalWrapper.appendChild(moonWrapper); digitalWrapper.appendChild(weekWrapper); - var appendClocks = function (condition, pos1, pos2) { - var padding = [0, 0, 0, 0]; + const appendClocks = (condition, pos1, pos2) => { + const padding = [0, 0, 0, 0]; padding[placement === condition ? pos1 : pos2] = "20px"; analogWrapper.style.padding = padding.join(" "); if (placement === condition) { diff --git a/modules/default/clock/clock_styles.css b/modules/default/clock/clock_styles.css index 839336be..0e74fd7a 100644 --- a/modules/default/clock/clock_styles.css +++ b/modules/default/clock/clock_styles.css @@ -17,7 +17,7 @@ width: 6px; height: 6px; margin: -3px 0 0 -3px; - background: white; + background: var(--color-text-bright); border-radius: 3px; content: ""; display: block; @@ -29,9 +29,9 @@ position: absolute; top: 50%; left: 50%; - margin: -2px 0 -2px -25%; /* numbers much match negative length & thickness */ + margin: -2px 0 -2px -25%; /* numbers must match negative length & thickness */ padding: 2px 0 2px 25%; /* indicator length & thickness */ - background: white; + background: var(--color-text-bright); transform-origin: 100% 50%; border-radius: 3px 0 0 3px; } @@ -44,7 +44,7 @@ left: 50%; margin: -35% -2px 0; /* numbers must match negative length & thickness */ padding: 35% 2px 0; /* indicator length & thickness */ - background: white; + background: var(--color-text-bright); transform-origin: 50% 100%; border-radius: 3px 0 0 3px; } @@ -57,7 +57,7 @@ left: 50%; margin: -38% -1px 0 0; /* numbers must match negative length & thickness */ padding: 38% 1px 0 0; /* indicator length & thickness */ - background: #888; + background: var(--color-text); transform-origin: 50% 100%; } diff --git a/modules/default/compliments/compliments.js b/modules/default/compliments/compliments.js index 6613a2c8..054a409f 100644 --- a/modules/default/compliments/compliments.js +++ b/modules/default/compliments/compliments.js @@ -39,37 +39,35 @@ Module.register("compliments", { this.lastComplimentIndex = -1; - var self = this; if (this.config.remoteFile !== null) { - this.complimentFile(function (response) { - self.config.compliments = JSON.parse(response); - self.updateDom(); + this.complimentFile((response) => { + this.config.compliments = JSON.parse(response); + this.updateDom(); }); } // Schedule update timer. - setInterval(function () { - self.updateDom(self.config.fadeSpeed); + setInterval(() => { + this.updateDom(this.config.fadeSpeed); }, this.config.updateInterval); }, - /* randomIndex(compliments) + /** * Generate a random index for a list of compliments. * - * argument compliments Array - Array with compliments. - * - * return Number - Random index. + * @param {string[]} compliments Array with compliments. + * @returns {number} a random index of given array */ randomIndex: function (compliments) { if (compliments.length === 1) { return 0; } - var generate = function () { + const generate = function () { return Math.floor(Math.random() * compliments.length); }; - var complimentIndex = generate(); + let complimentIndex = generate(); while (complimentIndex === this.lastComplimentIndex) { complimentIndex = generate(); @@ -80,15 +78,15 @@ Module.register("compliments", { return complimentIndex; }, - /* complimentArray() + /** * Retrieve an array of compliments for the time of the day. * - * return compliments Array - Array with compliments for the time of the day. + * @returns {string[]} array with compliments for the time of the day. */ complimentArray: function () { - var hour = moment().hour(); - var date = this.config.mockDate ? this.config.mockDate : moment().format("YYYY-MM-DD"); - var compliments; + const hour = moment().hour(); + const date = this.config.mockDate ? this.config.mockDate : moment().format("YYYY-MM-DD"); + let compliments; if (hour >= this.config.morningStartTime && hour < this.config.morningEndTime && this.config.compliments.hasOwnProperty("morning")) { compliments = this.config.compliments.morning.slice(0); @@ -99,7 +97,7 @@ Module.register("compliments", { } if (typeof compliments === "undefined") { - compliments = new Array(); + compliments = []; } if (this.currentWeatherType in this.config.compliments) { @@ -108,7 +106,7 @@ Module.register("compliments", { compliments.push.apply(compliments, this.config.compliments.anytime); - for (var entry in this.config.compliments) { + for (let entry in this.config.compliments) { if (new RegExp(entry).test(date)) { compliments.push.apply(compliments, this.config.compliments[entry]); } @@ -117,11 +115,13 @@ Module.register("compliments", { return compliments; }, - /* complimentFile(callback) + /** * Retrieve a file from the local filesystem + * + * @param {Function} callback Called when the file is retrieved. */ complimentFile: function (callback) { - var xobj = new XMLHttpRequest(), + const xobj = new XMLHttpRequest(), isRemote = this.config.remoteFile.indexOf("http://") === 0 || this.config.remoteFile.indexOf("https://") === 0, path = isRemote ? this.config.remoteFile : this.file(this.config.remoteFile); xobj.overrideMimeType("application/json"); @@ -134,16 +134,16 @@ Module.register("compliments", { xobj.send(null); }, - /* complimentArray() + /** * Retrieve a random compliment. * - * return compliment string - A compliment. + * @returns {string} a compliment */ randomCompliment: function () { // get the current time of day compliments list - var compliments = this.complimentArray(); + const compliments = this.complimentArray(); // variable for index to next message to display - let index = 0; + let index; // are we randomizing if (this.config.random) { // yes @@ -159,16 +159,16 @@ Module.register("compliments", { // Override dom generator. getDom: function () { - var wrapper = document.createElement("div"); + const wrapper = document.createElement("div"); wrapper.className = this.config.classes ? this.config.classes : "thin xlarge bright pre-line"; // get the compliment text - var complimentText = this.randomCompliment(); + const complimentText = this.randomCompliment(); // split it into parts on newline text - var parts = complimentText.split("\n"); + const parts = complimentText.split("\n"); // create a span to hold it all - var compliment = document.createElement("span"); + const compliment = document.createElement("span"); // process all the parts of the compliment text - for (var part of parts) { + for (const part of parts) { // create a text element for each part compliment.appendChild(document.createTextNode(part)); // add a break ` diff --git a/modules/default/defaultmodules.js b/modules/default/defaultmodules.js index 9bdcbe95..46bb5b87 100644 --- a/modules/default/defaultmodules.js +++ b/modules/default/defaultmodules.js @@ -1,13 +1,10 @@ -/* Magic Mirror - * Default Modules List +/* Magic Mirror Default Modules List + * Modules listed below can be loaded without the 'default/' prefix. Omitting the default folder name. * * By Michael Teeuw https://michaelteeuw.nl * MIT Licensed. */ - -// Modules listed below can be loaded without the 'default/' prefix. Omitting the default folder name. - -var defaultModules = ["alert", "calendar", "clock", "compliments", "currentweather", "helloworld", "newsfeed", "weatherforecast", "updatenotification", "weather"]; +const defaultModules = ["alert", "calendar", "clock", "compliments", "currentweather", "helloworld", "newsfeed", "weatherforecast", "updatenotification", "weather"]; /*************** DO NOT EDIT THE LINE BELOW ***************/ if (typeof module !== "undefined") { diff --git a/modules/default/newsfeed/newsfeed.css b/modules/default/newsfeed/newsfeed.css index 6f32b2e5..ea65eca2 100644 --- a/modules/default/newsfeed/newsfeed.css +++ b/modules/default/newsfeed/newsfeed.css @@ -12,3 +12,12 @@ iframe.newsfeed-fullarticle { bottom: inherit; top: -90px; } + +.newsfeed-list { + list-style: none; +} + +.newsfeed-list li { + text-align: justify; + margin-bottom: 0.5em; +} diff --git a/modules/default/newsfeed/newsfeed.js b/modules/default/newsfeed/newsfeed.js index 441984f4..7e21f8a8 100644 --- a/modules/default/newsfeed/newsfeed.js +++ b/modules/default/newsfeed/newsfeed.js @@ -14,6 +14,7 @@ Module.register("newsfeed", { encoding: "UTF-8" //ISO-8859-1 } ], + showAsList: false, showSourceTitle: true, showPublishDate: true, broadcastNewsFeeds: true, @@ -89,8 +90,8 @@ Module.register("newsfeed", { this.loaded = true; this.error = null; - } else if (notification === "INCORRECT_URL") { - this.error = `Incorrect url: ${payload.url}`; + } else if (notification === "NEWSFEED_ERROR") { + this.error = this.translate(payload.error_type); this.scheduleUpdateInterval(); } }, @@ -128,6 +129,10 @@ Module.register("newsfeed", { } const item = this.newsItems[this.activeItem]; + const items = this.newsItems.map(function (item) { + item.publishDate = moment(new Date(item.pubdate)).fromNow(); + return item; + }); return { loaded: true, @@ -135,7 +140,8 @@ Module.register("newsfeed", { sourceTitle: item.sourceTitle, publishDate: moment(new Date(item.pubdate)).fromNow(), title: item.title, - description: item.description + description: item.description, + items: items }; }, @@ -183,16 +189,15 @@ Module.register("newsfeed", { } if (this.config.prohibitedWords.length > 0) { - newsItems = newsItems.filter(function (value) { + newsItems = newsItems.filter(function (item) { for (let word of this.config.prohibitedWords) { - if (value["title"].toLowerCase().indexOf(word.toLowerCase()) > -1) { + if (item.title.toLowerCase().indexOf(word.toLowerCase()) > -1) { return false; } } return true; }, this); } - newsItems.forEach((item) => { //Remove selected tags from the beginning of rss feed items (title or description) if (this.config.removeStartTags === "title" || this.config.removeStartTags === "both") { diff --git a/modules/default/newsfeed/newsfeed.njk b/modules/default/newsfeed/newsfeed.njk index dc9ccad6..2b037dcc 100644 --- a/modules/default/newsfeed/newsfeed.njk +++ b/modules/default/newsfeed/newsfeed.njk @@ -1,26 +1,59 @@ {% if loaded %} -
- {% if (config.showSourceTitle and sourceTitle) or config.showPublishDate %} -
- {% if sourceTitle and config.showSourceTitle %} - {{ sourceTitle }}{% if config.showPublishDate %}, {% else %}: {% endif %} - {% endif %} - {% if config.showPublishDate %} - {{ publishDate }}: - {% endif %} + {% if config.showAsList %} +
    + {% for item in items %} +
  • + {% if (config.showSourceTitle and item.sourceTitle) or config.showPublishDate %} +
    + {% if item.sourceTitle and config.showSourceTitle %} + {{ item.sourceTitle }}{% if config.showPublishDate %}, {% else %}: {% endif %} + {% endif %} + {% if config.showPublishDate %} + {{ item.publishDate }}: + {% endif %} +
    + {% endif %} +
    + {{ item.title }} +
    + {% if config.showDescription %} +
    + {% if config.truncDescription %} + {{ item.description | truncate(config.lengthDescription) }} + {% else %} + {{ item.description }} + {% endif %} +
    + {% endif %} +
  • + {% endfor %} +
+ {% else %} +
+ {% if (config.showSourceTitle and sourceTitle) or config.showPublishDate %} +
+ {% if sourceTitle and config.showSourceTitle %} + {{ sourceTitle }}{% if config.showPublishDate %}, {% else %}: {% endif %} + {% endif %} + {% if config.showPublishDate %} + {{ publishDate }}: + {% endif %} +
+ {% endif %} +
+ {{ title }}
- {% endif %} -
- {{ title }} -
-
- {% if config.truncDescription %} - {{ description | truncate(config.lengthDescription) }} - {% else %} - {{ description }} + {% if config.showDescription %} +
+ {% if config.truncDescription %} + {{ description | truncate(config.lengthDescription) }} + {% else %} + {{ description }} + {% endif %} +
{% endif %}
-
+ {% endif %} {% elseif error %}
{{ "MODULE_CONFIG_ERROR" | translate({MODULE_NAME: "Newsfeed", ERROR: error}) | safe }} diff --git a/modules/default/newsfeed/newsfeedfetcher.js b/modules/default/newsfeed/newsfeedfetcher.js index d4db511d..6dd8683a 100644 --- a/modules/default/newsfeed/newsfeedfetcher.js +++ b/modules/default/newsfeed/newsfeedfetcher.js @@ -6,6 +6,7 @@ */ const Log = require("logger"); const FeedMe = require("feedme"); +const NodeHelper = require("node_helper"); const fetch = require("node-fetch"); const iconv = require("iconv-lite"); @@ -84,12 +85,13 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings }; fetch(url, { headers: headers }) + .then(NodeHelper.checkFetchStatus) + .then((response) => { + response.body.pipe(iconv.decodeStream(encoding)).pipe(parser); + }) .catch((error) => { fetchFailedCallback(this, error); scheduleTimer(); - }) - .then((res) => { - res.body.pipe(iconv.decodeStream(encoding)).pipe(parser); }); }; diff --git a/modules/default/newsfeed/node_helper.js b/modules/default/newsfeed/node_helper.js index 6fd461a1..32656a9f 100644 --- a/modules/default/newsfeed/node_helper.js +++ b/modules/default/newsfeed/node_helper.js @@ -27,8 +27,8 @@ module.exports = NodeHelper.create({ * Creates a fetcher for a new feed if it doesn't exist yet. * Otherwise it reuses the existing one. * - * @param {object} feed The feed object. - * @param {object} config The configuration object. + * @param {object} feed The feed object + * @param {object} config The configuration object */ createFetcher: function (feed, config) { const url = feed.url || ""; @@ -38,13 +38,14 @@ module.exports = NodeHelper.create({ try { new URL(url); } catch (error) { - this.sendSocketNotification("INCORRECT_URL", { url: url }); + Log.error("Newsfeed Error. Malformed newsfeed url: ", url, error); + this.sendSocketNotification("NEWSFEED_ERROR", { error_type: "MODULE_ERROR_MALFORMED_URL" }); return; } let fetcher; if (typeof this.fetchers[url] === "undefined") { - Log.log("Create new news fetcher for url: " + url + " - Interval: " + reloadInterval); + Log.log("Create new newsfetcher for url: " + url + " - Interval: " + reloadInterval); fetcher = new NewsfeedFetcher(url, reloadInterval, encoding, config.logFeedWarnings); fetcher.onReceive(() => { @@ -52,15 +53,16 @@ module.exports = NodeHelper.create({ }); fetcher.onError((fetcher, error) => { - this.sendSocketNotification("FETCH_ERROR", { - url: fetcher.url(), - error: error + Log.error("Newsfeed Error. Could not fetch newsfeed: ", url, error); + let error_type = NodeHelper.checkFetchError(error); + this.sendSocketNotification("NEWSFEED_ERROR", { + error_type }); }); this.fetchers[url] = fetcher; } else { - Log.log("Use existing news fetcher for url: " + url); + Log.log("Use existing newsfetcher for url: " + url); fetcher = this.fetchers[url]; fetcher.setReloadInterval(reloadInterval); fetcher.broadcastItems(); diff --git a/modules/default/updatenotification/updatenotification.js b/modules/default/updatenotification/updatenotification.js index c67205a7..7d416852 100644 --- a/modules/default/updatenotification/updatenotification.js +++ b/modules/default/updatenotification/updatenotification.js @@ -5,33 +5,35 @@ * MIT Licensed. */ Module.register("updatenotification", { + // Define module defaults defaults: { updateInterval: 10 * 60 * 1000, // every 10 minutes refreshInterval: 24 * 60 * 60 * 1000, // one day ignoreModules: [], - timeout: 1000 + timeout: 5000 }, suspended: false, moduleList: {}, + // Override start method. start: function () { - var self = this; - Log.log("Start updatenotification"); + Log.info("Starting module: " + this.name); setInterval(() => { - self.moduleList = {}; - self.updateDom(2); - }, self.config.refreshInterval); + this.moduleList = {}; + this.updateDom(2); + }, this.config.refreshInterval); }, notificationReceived: function (notification, payload, sender) { if (notification === "DOM_OBJECTS_CREATED") { this.sendSocketNotification("CONFIG", this.config); this.sendSocketNotification("MODULES", Module.definitions); - //this.hide(0, { lockString: self.identifier }); + //this.hide(0, { lockString: this.identifier }); } }, + // Override socket notification handler. socketNotificationReceived: function (notification, payload) { if (notification === "STATUS") { this.updateUI(payload); @@ -39,13 +41,12 @@ Module.register("updatenotification", { }, updateUI: function (payload) { - var self = this; if (payload && payload.behind > 0) { // if we haven't seen info for this module if (this.moduleList[payload.module] === undefined) { // save it this.moduleList[payload.module] = payload; - self.updateDom(2); + this.updateDom(2); } //self.show(1000, { lockString: self.identifier }); } else if (payload && payload.behind === 0) { @@ -53,41 +54,41 @@ Module.register("updatenotification", { if (this.moduleList[payload.module] !== undefined) { // remove it delete this.moduleList[payload.module]; - self.updateDom(2); + this.updateDom(2); } } }, diffLink: function (module, text) { - var localRef = module.hash; - var remoteRef = module.tracking.replace(/.*\//, ""); + const localRef = module.hash; + const remoteRef = module.tracking.replace(/.*\//, ""); return '' + text + ""; }, // Override dom generator. getDom: function () { - var wrapper = document.createElement("div"); + const wrapper = document.createElement("div"); if (this.suspended === false) { // process the hash of module info found - for (var key of Object.keys(this.moduleList)) { + for (const key of Object.keys(this.moduleList)) { let m = this.moduleList[key]; - var message = document.createElement("div"); + const message = document.createElement("div"); message.className = "small bright"; - var icon = document.createElement("i"); + const icon = document.createElement("i"); icon.className = "fa fa-exclamation-circle"; icon.innerHTML = " "; message.appendChild(icon); - var updateInfoKeyName = m.behind === 1 ? "UPDATE_INFO_SINGLE" : "UPDATE_INFO_MULTIPLE"; + const updateInfoKeyName = m.behind === 1 ? "UPDATE_INFO_SINGLE" : "UPDATE_INFO_MULTIPLE"; - var subtextHtml = this.translate(updateInfoKeyName, { + let subtextHtml = this.translate(updateInfoKeyName, { COMMIT_COUNT: m.behind, BRANCH_NAME: m.current }); - var text = document.createElement("span"); + const text = document.createElement("span"); if (m.module === "default") { text.innerHTML = this.translate("UPDATE_NOTIFICATION"); subtextHtml = this.diffLink(m, subtextHtml); @@ -100,7 +101,7 @@ Module.register("updatenotification", { wrapper.appendChild(message); - var subtext = document.createElement("div"); + const subtext = document.createElement("div"); subtext.innerHTML = subtextHtml; subtext.className = "xsmall dimmed"; wrapper.appendChild(subtext); diff --git a/modules/default/weather/forecast.njk b/modules/default/weather/forecast.njk index 8fa04298..92a575cf 100644 --- a/modules/default/weather/forecast.njk +++ b/modules/default/weather/forecast.njk @@ -5,24 +5,30 @@ {% set forecast = forecast.slice(0, numSteps) %} {% for f in forecast %} - {% if (currentStep == 0) %} + {% if (currentStep == 0) and config.ignoreToday == false %} {{ "TODAY" | translate }} - {% elif (currentStep == 1) %} + {% elif (currentStep == 1) and config.ignoreToday == false %} {{ "TOMORROW" | translate }} {% else %} {{ f.date.format('ddd') }} {% endif %} - {{ f.maxTemperature | roundValue | unit("temperature") }} + {{ f.maxTemperature | roundValue | unit("temperature") | decimalSymbol }} - {{ f.minTemperature | roundValue | unit("temperature") }} + {{ f.minTemperature | roundValue | unit("temperature") | decimalSymbol }} {% if config.showPrecipitationAmount %} - - {{ f.precipitation | unit("precip") }} - + {% if f.precipitationUnits %} + + {{ f.precipitation }}{{ f.precipitationUnits }} + + {% else %} + + {{ f.precipitation | unit("precip") }} + + {% endif %} {% endif %} {% set currentStep = currentStep + 1 %} diff --git a/modules/default/weather/hourly.njk b/modules/default/weather/hourly.njk index 3950ece2..f58d31a0 100644 --- a/modules/default/weather/hourly.njk +++ b/modules/default/weather/hourly.njk @@ -11,9 +11,15 @@ {{ hour.temperature | roundValue | unit("temperature") }} {% if config.showPrecipitationAmount %} - - {{ hour.precipitation | unit("precip") }} - + {% if hour.precipitationUnits %} + + {{ hour.precipitation }}{{ hour.precipitationUnits }} + + {% else %} + + {{ hour.precipitation | unit("precip") }} + + {% endif %} {% endif %} {% set currentStep = currentStep + 1 %} diff --git a/modules/default/weather/providers/envcanada.js b/modules/default/weather/providers/envcanada.js new file mode 100644 index 00000000..db0773ea --- /dev/null +++ b/modules/default/weather/providers/envcanada.js @@ -0,0 +1,649 @@ +/* global WeatherProvider, WeatherObject */ + +/* Magic Mirror + * Module: Weather + * Provider: Environment Canada (EC) + * + * This class is a provider for Environment Canada MSC Datamart + * Note that this is only for Canadian locations and does not require an API key (access is anonymous) + * + * EC Documentation at following links: + * https://dd.weather.gc.ca/citypage_weather/schema/ + * https://eccc-msc.github.io/open-data/msc-datamart/readme_en/ + * + * This module supports Canadian locations only and requires 2 additional config parms: + * + * siteCode - the city/town unique identifier for which weather is to be displayed. Format is 's0000000'. + * + * provCode - the 2-character province code for the selected city/town. + * + * Example: for Toronto, Ontario, the following parms would be used + * + * siteCode: 's0000458', + * provCode: 'ON' + * + * To determine the siteCode and provCode values for a Canadian city/town, look at the Environment Canada document + * at https://dd.weather.gc.ca/citypage_weather/docs/site_list_en.csv (or site_list_fr.csv). There you will find a table + * with locations you can search under column B (English Names), with the corresponding siteCode under + * column A (Codes) and provCode under column C (Province). + * + * Original by Kevin Godin + * + * License to use Environment Canada (EC) data is detailed here: + * https://eccc-msc.github.io/open-data/licence/readme_en/ + * + */ + +WeatherProvider.register("envcanada", { + // Set the name of the provider for debugging and alerting purposes (eg. provide eye-catcher) + providerName: "Environment Canada", + + // Set the default config properties that is specific to this provider + defaults: { + siteCode: "s1234567", + provCode: "ON" + }, + + // + // Set config values (equates to weather module config values). Also set values pertaining to caching of + // Today's temperature forecast (for use in the Forecast functions below) + // + setConfig: function (config) { + this.config = config; + + this.todayTempCacheMin = 0; + this.todayTempCacheMax = 0; + this.todayCached = false; + this.cacheCurrentTemp = 999; + }, + + // + // Called when the weather provider is started + // + start: function () { + Log.info(`Weather provider: ${this.providerName} started.`); + this.setFetchedLocation(this.config.location); + + // Ensure kmH are ignored since these are custom-handled by this Provider + + this.config.useKmh = false; + }, + + // + // Override the fetchCurrentWeather method to query EC and construct a Current weather object + // + fetchCurrentWeather() { + this.fetchData(this.getUrl(), "GET") + .then((data) => { + if (!data) { + // Did not receive usable new data. + return; + } + const currentWeather = this.generateWeatherObjectFromCurrentWeather(data); + + this.setCurrentWeather(currentWeather); + }) + .catch(function (request) { + Log.error("Could not load EnvCanada site data ... ", request); + }) + .finally(() => this.updateAvailable()); + }, + + // + // Override the fetchWeatherForecast method to query EC and construct Forecast weather objects + // + fetchWeatherForecast() { + this.fetchData(this.getUrl(), "GET") + .then((data) => { + if (!data) { + // Did not receive usable new data. + return; + } + const forecastWeather = this.generateWeatherObjectsFromForecast(data); + + this.setWeatherForecast(forecastWeather); + }) + .catch(function (request) { + Log.error("Could not load EnvCanada forecast data ... ", request); + }) + .finally(() => this.updateAvailable()); + }, + + // + // Override the fetchWeatherHourly method to query EC and construct Forecast weather objects + // + fetchWeatherHourly() { + this.fetchData(this.getUrl(), "GET") + .then((data) => { + if (!data) { + // Did not receive usable new data. + return; + } + const hourlyWeather = this.generateWeatherObjectsFromHourly(data); + + this.setWeatherHourly(hourlyWeather); + }) + .catch(function (request) { + Log.error("Could not load EnvCanada hourly data ... ", request); + }) + .finally(() => this.updateAvailable()); + }, + + // + // Override fetchData function to handle XML document (base function assumes JSON) + // + fetchData: function (url, method = "GET", data = null) { + return new Promise(function (resolve, reject) { + var request = new XMLHttpRequest(); + request.open(method, url, true); + request.onreadystatechange = function () { + if (this.readyState === 4) { + if (this.status === 200) { + resolve(this.responseXML); + } else { + reject(request); + } + } + }; + request.send(); + }); + }, + + ////////////////////////////////////////////////////////////////////////////////// + // + // Environment Canada methods - not part of the standard Provider methods + // + ////////////////////////////////////////////////////////////////////////////////// + + // + // Build the EC URL based on the Site Code and Province Code specified in the config parms. Note that the + // URL defaults to the Englsih version simply because there is no language dependancy in the data + // being accessed. This is only pertinent when using the EC data elements that contain a textual forecast. + // + // Also note that access is supported through a proxy service (thingproxy.freeboard.io) to mitigate + // CORS errors when accessing EC + // + getUrl() { + var path = "https://thingproxy.freeboard.io/fetch/https://dd.weather.gc.ca/citypage_weather/xml/" + this.config.provCode + "/" + this.config.siteCode + "_e.xml"; + + return path; + }, + + // + // Generate a WeatherObject based on current EC weather conditions + // + + generateWeatherObjectFromCurrentWeather(ECdoc) { + const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + + // There are instances where EC will update weather data and current temperature will not be + // provided. While this is a defect in the EC systems, we need to accommodate to avoid a current temp + // of NaN being displayed. Therefore... whenever we get a valid current temp from EC, we will cache + // the value. Whenever EC data is missing current temp, we will provide the cached value + // instead. This is reasonable since the cached value will typically be accurate within the previous + // hour. The only time this does not work as expected is when MM is restarted and the first query to + // EC finds no current temp. In this scenario, MM will end up displaying a current temp of null; + + if (ECdoc.querySelector("siteData currentConditions temperature").textContent) { + currentWeather.temperature = this.convertTemp(ECdoc.querySelector("siteData currentConditions temperature").textContent); + this.cacheCurrentTemp = currentWeather.temperature; + } else { + currentWeather.temperature = this.cacheCurrentTemp; + } + + currentWeather.windSpeed = this.convertWind(ECdoc.querySelector("siteData currentConditions wind speed").textContent); + + currentWeather.windDirection = ECdoc.querySelector("siteData currentConditions wind bearing").textContent; + + currentWeather.humidity = ECdoc.querySelector("siteData currentConditions relativeHumidity").textContent; + + // Ensure showPrecipitationAmount is forced to false. EC does not really provide POP for current day + // and this feature for the weather module (current only) is sort of broken in that it wants + // to say POP but will display precip as an accumulated amount vs. a percentage. + + this.config.showPrecipitationAmount = false; + + // + // If the module config wants to showFeelsLike... default to the current temperature. + // Check for EC wind chill and humidex values and overwrite the feelsLikeTemp value. + // This assumes that the EC current conditions will never contain both a wind chill + // and humidex temperature. + // + + if (this.config.showFeelsLike) { + currentWeather.feelsLikeTemp = currentWeather.temperature; + + if (ECdoc.querySelector("siteData currentConditions windChill")) { + currentWeather.feelsLikeTemp = this.convertTemp(ECdoc.querySelector("siteData currentConditions windChill").textContent); + } + + if (ECdoc.querySelector("siteData currentConditions humidex")) { + currentWeather.feelsLikeTemp = this.convertTemp(ECdoc.querySelector("siteData currentConditions humidex").textContent); + } + } + + // + // Need to map EC weather icon to MM weatherType values + // + + currentWeather.weatherType = this.convertWeatherType(ECdoc.querySelector("siteData currentConditions iconCode").textContent); + + // + // Capture the sunrise and sunset values from EC data + // + + var sunList = ECdoc.querySelectorAll("siteData riseSet dateTime"); + + currentWeather.sunrise = moment(sunList[1].querySelector("timeStamp").textContent, "YYYYMMDDhhmmss"); + currentWeather.sunset = moment(sunList[3].querySelector("timeStamp").textContent, "YYYYMMDDhhmmss"); + + return currentWeather; + }, + + // + // Generate an array of WeatherObjects based on EC weather forecast + // + + generateWeatherObjectsFromForecast(ECdoc) { + // Declare an array to hold each day's forecast object + + const days = []; + + var weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + + var foreBaseDates = ECdoc.querySelectorAll("siteData forecastGroup dateTime"); + var baseDate = foreBaseDates[1].querySelector("timeStamp").textContent; + + weather.date = moment(baseDate, "YYYYMMDDhhmmss"); + + var foreGroup = ECdoc.querySelectorAll("siteData forecastGroup forecast"); + + // For simplicity, we will only accumulate precipitation and will not try to break out + // rain vs snow accumulations + + weather.rain = null; + weather.snow = null; + weather.precipitation = null; + + // + // The EC forecast is held in a 12-element array - Elements 0 to 11 - with each day encompassing + // 2 elements. the first element for a day details the Today (daytime) forecast while the second + // element details the Tonight (nightime) forecast. Element 0 is always for the current day. + // + // However... the forecast is somewhat 'rolling'. + // + // If the EC forecast is queried in the morning, then Element 0 will contain Current + // Today and Element 1 will contain Current Tonight. From there, the next 5 days of forecast will be + // contained in Elements 2/3, 4/5, 6/7, 8/9, and 10/11. This module will create a 6-day forecast using + // all of these Elements. + // + // But, if the EC forecast is queried in late afternoon, the Current Today forecast will be rolled + // off and Element 0 will contain Current Tonight. From there, the next 5 days will be contained in + // Elements 1/2, 3/4, 5/6, 7/8, and 9/10. As well, Elelement 11 will contain a forecast for a 6th day, + // but only for the Today portion (not Tonight). This module will create a 6-day forecast using + // Elements 0 to 11, and will ignore the additional Todat forecast in Element 11. + // + // We need to determine if Element 0 is showing the forecast for Current Today or Current Tonight. + // This is required to understand how Min and Max temperature will be determined, and to understand + // where the next day's (aka Tomorrow's) forecast is located in the forecast array. + // + + var nextDay = 0; + var lastDay = 0; + var currentTemp = ECdoc.querySelector("siteData currentConditions temperature").textContent; + + // + // If the first Element is Current Today, look at Current Today and Current Tonight for the current day. + // + + if (foreGroup[0].querySelector("period[textForecastName='Today']")) { + this.todaytempCacheMin = 0; + this.todaytempCacheMax = 0; + this.todayCached = true; + + this.setMinMaxTemps(weather, foreGroup, 0, true, currentTemp); + + this.setPrecipitation(weather, foreGroup, 0); + + // + // Set the Element number that will reflect where the next day's forecast is located. Also set + // the Element number where the end of the forecast will be. This is important because of the + // rolling nature of the EC forecast. In the current scenario (Today and Tonight are present + // in elements 0 and 11, we know that we will have 6 full days of forecasts and we will use + // them. We will set lastDay such that we iterate through all 12 elements of the forecast. + // + + nextDay = 2; + lastDay = 12; + } + + // + // If the first Element is Current Tonight, look at Tonight only for the current day. + // + if (foreGroup[0].querySelector("period[textForecastName='Tonight']")) { + this.setMinMaxTemps(weather, foreGroup, 0, false, currentTemp); + + this.setPrecipitation(weather, foreGroup, 0); + + // + // Set the Element number that will reflect where the next day's forecast is located. Also set + // the Element number where the end of the forecast will be. This is important because of the + // rolling nature of the EC forecast. In the current scenario (only Current Tonight is present + // in Element 0, we know that we will have 6 full days of forecasts PLUS a half-day and + // forecast in the final element. Because we will only use full day forecasts, we set the + // lastDay number to ensure we ignore that final half-day (in forecast Element 11). + // + + nextDay = 1; + lastDay = 11; + } + + // + // Need to map EC weather icon to MM weatherType values. Always pick the first Element's icon to + // reflect either Today or Tonight depending on what the forecast is showing in Element 0. + // + + weather.weatherType = this.convertWeatherType(foreGroup[0].querySelector("abbreviatedForecast iconCode").textContent); + + // Push the weather object into the forecast array. + + days.push(weather); + + // + // Now do the the rest of the forecast starting at nextDay. We will process each day using 2 EC + // forecast Elements. This will address the fact that the EC forecast always includes Today and + // Tonight for each day. This is why we iterate through the forecast by a a count of 2, with each + // iteration looking at the current Element and the next Element. + // + + var lastDate = moment(baseDate, "YYYYMMDDhhmmss"); + + for (var stepDay = nextDay; stepDay < lastDay; stepDay += 2) { + var weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + + // Add 1 to the date to reflect the current forecast day we are building + + lastDate = lastDate.add(1, "day"); + weather.date = moment(lastDate, "X"); + + // Capture the temperatures for the current Element and the next Element in order to set + // the Min and Max temperatures for the forecast + + this.setMinMaxTemps(weather, foreGroup, stepDay, true, currentTemp); + + weather.rain = null; + weather.snow = null; + weather.precipitation = null; + + this.setPrecipitation(weather, foreGroup, stepDay); + + // + // Need to map EC weather icon to MM weatherType values. Always pick the first Element icon. + // + + weather.weatherType = this.convertWeatherType(foreGroup[stepDay].querySelector("abbreviatedForecast iconCode").textContent); + + // Push the weather object into the forecast array. + + days.push(weather); + } + + return days; + }, + + // + // Generate an array of WeatherObjects based on EC hourly weather forecast + // + + generateWeatherObjectsFromHourly(ECdoc) { + // Declare an array to hold each hour's forecast object + + const hours = []; + + // Get local timezone UTC offset so that each hourly time can be calculated properly + + var baseHours = ECdoc.querySelectorAll("siteData hourlyForecastGroup dateTime"); + var hourOffset = baseHours[1].getAttribute("UTCOffset"); + + // + // The EC hourly forecast is held in a 24-element array - Elements 0 to 23 - with Element 0 holding + // the forecast for the next 'on the hour' timeslot. This means the array is a rolling 24 hours. + // + + var hourGroup = ECdoc.querySelectorAll("siteData hourlyForecastGroup hourlyForecast"); + + for (var stepHour = 0; stepHour < 24; stepHour += 1) { + var weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + + // Determine local time by applying UTC offset to the forecast timestamp + + var foreTime = moment(hourGroup[stepHour].getAttribute("dateTimeUTC"), "YYYYMMDDhhmmss"); + var currTime = foreTime.add(hourOffset, "hours"); + weather.date = moment(currTime, "X"); + + // Capture the temperature + + weather.temperature = this.convertTemp(hourGroup[stepHour].querySelector("temperature").textContent); + + // Capture Likelihood of Precipitation (LOP) and unit-of-measure values + + var precipLOP = hourGroup[stepHour].querySelector("lop").textContent * 1.0; + + if (precipLOP > 0) { + weather.precipitation = precipLOP; + weather.precipitationUnits = hourGroup[stepHour].querySelector("lop").getAttribute("units"); + } + + // + // Need to map EC weather icon to MM weatherType values. Always pick the first Element icon. + // + + weather.weatherType = this.convertWeatherType(hourGroup[stepHour].querySelector("iconCode").textContent); + + // Push the weather object into the forecast array. + + hours.push(weather); + } + + return hours; + }, + // + // Determine Min and Max temp based on a supplied Forecast Element index and a boolen that denotes if + // the next Forecast element should be considered - i.e. look at Today *and* Tonight vs.Tonight-only + // + + setMinMaxTemps(weather, foreGroup, today, fullDay, currentTemp) { + var todayTemp = foreGroup[today].querySelector("temperatures temperature").textContent; + + var todayClass = foreGroup[today].querySelector("temperatures temperature").getAttribute("class"); + + // + // The following logic is largely aimed at accommodating the Current day's forecast whereby we + // can have either Current Today+Current Tonight or only Current Tonight. + // + // If fullDay is false, then we only have Tonight for the current day's forecast - meaning we have + // lost a min or max temp value for the day. Therefore, we will see if we were able to cache the the + // Today forecast for the current day. If we have, we will use them. If we do not have the cached values, + // it means that MM or the Computer has been restarted since the time EC rolled off Today from the + // forecast. In this scenario, we will simply default to the Current Conditions temperature and then + // check the Tonight temperature. + // + + if (fullDay === false) { + if (this.todayCached === true) { + weather.minTemperature = this.todayTempCacheMin; + weather.maxTemperature = this.todayTempCacheMax; + } else { + weather.minTemperature = this.convertTemp(currentTemp); + weather.maxTemperature = weather.minTemperature; + } + } + + // + // We will check to see if the current Element's temperature is Low or High and set weather values + // accordingly. We will also check the condition where fullDay is true *and* we are looking at forecast + // element 0. This is a special case where we will cache temperature values so that we have them later + // in the current day when the Current Today element rolls off and we have Current Tonight only. + // + + if (todayClass === "low") { + weather.minTemperature = this.convertTemp(todayTemp); + if (today === 0 && fullDay === true) { + this.todayTempCacheMin = weather.minTemperature; + } + } + + if (todayClass === "high") { + weather.maxTemperature = this.convertTemp(todayTemp); + if (today === 0 && fullDay === true) { + this.todayTempCacheMax = weather.maxTemperature; + } + } + + var nextTemp = foreGroup[today + 1].querySelector("temperatures temperature").textContent; + + var nextClass = foreGroup[today + 1].querySelector("temperatures temperature").getAttribute("class"); + + if (fullDay === true) { + if (nextClass === "low") { + weather.minTemperature = this.convertTemp(nextTemp); + } + + if (nextClass === "high") { + weather.maxTemperature = this.convertTemp(nextTemp); + } + } + + return; + }, + + // + // Check for a Precipitation forecast. EC can provide a forecast in 2 ways: either an accumulation figure + // or a POP percentage. If there is a POP, then that is what the module will show. If there is an accumulation, + // then it will be displayed ONLY if no POP is present. + // + // POP Logic: By default, we want to show the POP for 'daytime' since we are presuming that is what + // people are more interested in seeing. While EC provides a separate POP for daytime and nightime portions + // of each day, the weather module does not really allow for that view of a daily forecast. There we will + // ignore any nightime portion. There is an exception however! For the Current day, the EC data will only show + // the nightime forecast after a certain point in the afternoon. As such, we will be showing the nightime POP + // (if one exists) in that specific scenario. + // + // Accumulation Logic: Similar to POP, we want to show accumulation for 'daytime' since we presume that is what + // people are interested in seeing. While EC provides a separate accumulation for daytime and nightime portions + // of each day, the weather module does not really allow for that view of a daily forecast. There we will + // ignore any nightime portion. There is an exception however! For the Current day, the EC data will only show + // the nightime forecast after a certain point in that specific scenario. + // + + setPrecipitation(weather, foreGroup, today) { + if (foreGroup[today].querySelector("precipitation accumulation")) { + weather.precipitation = foreGroup[today].querySelector("precipitation accumulation amount").textContent * 1.0; + + weather.precipitationUnits = " " + foreGroup[today].querySelector("precipitation accumulation amount").getAttribute("units"); + + if (this.config.units === "imperial") { + if (weather.precipitationUnits === " cm") { + weather.precipitation = (weather.precipitation * 0.394).toFixed(2); + weather.precipitationUnits = " in"; + } + if (weather.precipitationUnits === " mm") { + weather.precipitation = (weather.precipitation * 0.0394).toFixed(2); + weather.precipitationUnits = " in"; + } + } + } + + // Check Today element for POP + + if (foreGroup[today].querySelector("abbreviatedForecast pop").textContent > 0) { + weather.precipitation = foreGroup[today].querySelector("abbreviatedForecast pop").textContent; + weather.precipitationUnits = foreGroup[today].querySelector("abbreviatedForecast pop").getAttribute("units"); + } + + return; + }, + + // + // Unit conversions + // + // + // Convert C to F temps + // + convertTemp(temp) { + if (this.config.tempUnits === "imperial") { + return 1.8 * temp + 32; + } else { + return temp; + } + }, + // + // Convert km/h to mph + // + convertWind(kilo) { + if (this.config.windUnits === "imperial") { + return kilo / 1.609344; + } else { + return kilo; + } + }, + + // + // Convert the icons to a more usable name. + // + convertWeatherType(weatherType) { + const weatherTypes = { + "00": "day-sunny", + "01": "day-sunny", + "02": "day-sunny-overcast", + "03": "day-cloudy", + "04": "day-cloudy", + "05": "day-cloudy", + "06": "day-sprinkle", + "07": "day-showers", + "08": "day-snow", + "09": "day-thunderstorm", + 10: "cloud", + 11: "showers", + 12: "rain", + 13: "rain", + 14: "sleet", + 15: "sleet", + 16: "snow", + 17: "snow", + 18: "snow", + 19: "thunderstorm", + 20: "cloudy", + 21: "cloudy", + 22: "day-cloudy", + 23: "day-haze", + 24: "fog", + 25: "snow-wind", + 26: "sleet", + 27: "sleet", + 28: "rain", + 29: "na", + 30: "night-clear", + 31: "night-clear", + 32: "night-partly-cloudy", + 33: "night-alt-cloudy", + 34: "night-alt-cloudy", + 35: "night-partly-cloudy", + 36: "night-alt-showers", + 37: "night-rain-mix", + 38: "night-alt-snow", + 39: "night-thunderstorm", + 40: "snow-wind", + 41: "tornado", + 42: "tornado", + 43: "windy", + 44: "smoke", + 45: "sandstorm", + 46: "thunderstorm", + 47: "thunderstorm", + 48: "tornado" + }; + + return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null; + } +}); diff --git a/modules/default/weather/providers/openweathermap.js b/modules/default/weather/providers/openweathermap.js index 2d0645fc..bbe74d3b 100755 --- a/modules/default/weather/providers/openweathermap.js +++ b/modules/default/weather/providers/openweathermap.js @@ -30,16 +30,14 @@ WeatherProvider.register("openweathermap", { fetchCurrentWeather() { this.fetchData(this.getUrl()) .then((data) => { - if (!data || !data.main || typeof data.main.temp === "undefined") { - // Did not receive usable new data. - // Maybe this needs a better check? - return; + if (this.config.weatherEndpoint === "/onecall") { + const weatherData = this.generateWeatherObjectsFromOnecall(data); + this.setCurrentWeather(weatherData.current); + this.setFetchedLocation(`${data.timezone}`); + } else { + const currentWeather = this.generateWeatherObjectFromCurrentWeather(data); + this.setCurrentWeather(currentWeather); } - - this.setFetchedLocation(`${data.name}, ${data.sys.country}`); - - const currentWeather = this.generateWeatherObjectFromCurrentWeather(data); - this.setCurrentWeather(currentWeather); }) .catch(function (request) { Log.error("Could not load data ... ", request); @@ -51,16 +49,15 @@ WeatherProvider.register("openweathermap", { fetchWeatherForecast() { this.fetchData(this.getUrl()) .then((data) => { - if (!data || !data.list || !data.list.length) { - // Did not receive usable new data. - // Maybe this needs a better check? - return; + if (this.config.weatherEndpoint === "/onecall") { + const weatherData = this.generateWeatherObjectsFromOnecall(data); + this.setWeatherForecast(weatherData.days); + this.setFetchedLocation(`${data.timezone}`); + } else { + const forecast = this.generateWeatherObjectsFromForecast(data.list); + this.setWeatherForecast(forecast); + this.setFetchedLocation(`${data.city.name}, ${data.city.country}`); } - - this.setFetchedLocation(`${data.city.name}, ${data.city.country}`); - - const forecast = this.generateWeatherObjectsFromForecast(data.list); - this.setWeatherForecast(forecast); }) .catch(function (request) { Log.error("Could not load data ... ", request); diff --git a/modules/default/weather/providers/smhi.js b/modules/default/weather/providers/smhi.js index a27b1300..efcf8bb0 100644 --- a/modules/default/weather/providers/smhi.js +++ b/modules/default/weather/providers/smhi.js @@ -74,7 +74,7 @@ WeatherProvider.register("smhi", { getClosestToCurrentTime(times) { let now = moment(); let minDiff = undefined; - for (time of times) { + for (const time of times) { let diff = Math.abs(moment(time.validTime).diff(now)); if (!minDiff || diff < Math.abs(moment(minDiff.validTime).diff(now))) { minDiff = time; @@ -149,13 +149,13 @@ WeatherProvider.register("smhi", { * @param coordinates */ convertWeatherDataGroupedByDay(allWeatherData, coordinates) { - var currentWeather; + let currentWeather; let result = []; let allWeatherObjects = this.fillInGaps(allWeatherData).map((weatherData) => this.convertWeatherDataToObject(weatherData, coordinates)); - var dayWeatherTypes = []; + let dayWeatherTypes = []; - for (weatherObject of allWeatherObjects) { + for (const weatherObject of allWeatherObjects) { //If its the first object or if a day change we need to reset the summary object if (!currentWeather || !currentWeather.date.isSame(weatherObject.date, "day")) { currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); @@ -216,12 +216,12 @@ WeatherProvider.register("smhi", { */ fillInGaps(data) { let result = []; - for (var i = 1; i < data.length; i++) { + for (const i = 1; i < data.length; i++) { let to = moment(data[i].validTime); let from = moment(data[i - 1].validTime); let hours = moment.duration(to.diff(from)).asHours(); // For each hour add a datapoint but change the validTime - for (var j = 0; j < hours; j++) { + for (const j = 0; j < hours; j++) { let current = Object.assign({}, data[i]); current.validTime = from.clone().add(j, "hours").toISOString(); result.push(current); diff --git a/modules/default/weather/providers/ukmetoffice.js b/modules/default/weather/providers/ukmetoffice.js index 11cee48f..27127806 100755 --- a/modules/default/weather/providers/ukmetoffice.js +++ b/modules/default/weather/providers/ukmetoffice.js @@ -81,6 +81,7 @@ WeatherProvider.register("ukmetoffice", { */ generateWeatherObjectFromCurrentWeather(currentWeatherData) { const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const location = currentWeatherData.SiteRep.DV.Location; // data times are always UTC let nowUtc = moment.utc(); @@ -88,8 +89,8 @@ WeatherProvider.register("ukmetoffice", { let timeInMins = nowUtc.diff(midnightUtc, "minutes"); // loop round each of the (5) periods, look for today (the first period may be yesterday) - for (var i in currentWeatherData.SiteRep.DV.Location.Period) { - let periodDate = moment.utc(currentWeatherData.SiteRep.DV.Location.Period[i].value.substr(0, 10), "YYYY-MM-DD"); + for (const period of location.Period) { + const periodDate = moment.utc(period.value.substr(0, 10), "YYYY-MM-DD"); // ignore if period is before today if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) { @@ -97,17 +98,17 @@ WeatherProvider.register("ukmetoffice", { if (moment().diff(periodDate, "minutes") > 0) { // loop round the reports looking for the one we are in // $ value specifies the time in minutes-of-the-day: 0, 180, 360,...1260 - for (var j in currentWeatherData.SiteRep.DV.Location.Period[i].Rep) { - let p = currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].$; + for (const rep of period.Rep) { + const p = rep.$; if (timeInMins >= p && timeInMins - 180 < p) { // finally got the one we want, so populate weather object - currentWeather.humidity = currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].H; - currentWeather.temperature = this.convertTemp(currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].T); - currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].F); - currentWeather.precipitation = parseInt(currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].Pp); - currentWeather.windSpeed = this.convertWindSpeed(currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].S); - currentWeather.windDirection = this.convertWindDirection(currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].D); - currentWeather.weatherType = this.convertWeatherType(currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].W); + currentWeather.humidity = rep.H; + currentWeather.temperature = this.convertTemp(rep.T); + currentWeather.feelsLikeTemp = this.convertTemp(rep.F); + currentWeather.precipitation = parseInt(rep.Pp); + currentWeather.windSpeed = this.convertWindSpeed(rep.S); + currentWeather.windDirection = this.convertWindDirection(rep.D); + currentWeather.weatherType = this.convertWeatherType(rep.W); } } } @@ -115,7 +116,7 @@ WeatherProvider.register("ukmetoffice", { } // determine the sunrise/sunset times - not supplied in UK Met Office data - let times = this.calcAstroData(currentWeatherData.SiteRep.DV.Location); + let times = this.calcAstroData(location); currentWeather.sunrise = times[0]; currentWeather.sunset = times[1]; @@ -130,21 +131,21 @@ WeatherProvider.register("ukmetoffice", { // loop round the (5) periods getting the data // for each period array, Day is [0], Night is [1] - for (var j in forecasts.SiteRep.DV.Location.Period) { + for (const period of forecasts.SiteRep.DV.Location.Period) { const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); // data times are always UTC - const dateStr = forecasts.SiteRep.DV.Location.Period[j].value; + const dateStr = period.value; let periodDate = moment.utc(dateStr.substr(0, 10), "YYYY-MM-DD"); // ignore if period is before today if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) { // populate the weather object weather.date = moment.utc(dateStr.substr(0, 10), "YYYY-MM-DD"); - weather.minTemperature = this.convertTemp(forecasts.SiteRep.DV.Location.Period[j].Rep[1].Nm); - weather.maxTemperature = this.convertTemp(forecasts.SiteRep.DV.Location.Period[j].Rep[0].Dm); - weather.weatherType = this.convertWeatherType(forecasts.SiteRep.DV.Location.Period[j].Rep[0].W); - weather.precipitation = parseInt(forecasts.SiteRep.DV.Location.Period[j].Rep[0].PPd); + weather.minTemperature = this.convertTemp(period.Rep[1].Nm); + weather.maxTemperature = this.convertTemp(period.Rep[0].Dm); + weather.weatherType = this.convertWeatherType(period.Rep[0].W); + weather.precipitation = parseInt(period.Rep[0].PPd); days.push(weather); } diff --git a/modules/default/weather/providers/ukmetofficedatahub.js b/modules/default/weather/providers/ukmetofficedatahub.js index 03e5fa5a..d096c33b 100644 --- a/modules/default/weather/providers/ukmetofficedatahub.js +++ b/modules/default/weather/providers/ukmetofficedatahub.js @@ -59,9 +59,7 @@ WeatherProvider.register("ukmetofficedatahub", { let queryStrings = "?"; queryStrings += "latitude=" + this.config.lat; queryStrings += "&longitude=" + this.config.lon; - if (this.config.appendLocationNameToHeader) { - queryStrings += "&includeLocationName=" + true; - } + queryStrings += "&includeLocationName=" + true; // Return URL, making sure there is a trailing "/" in the base URL. return this.config.apiBase + (this.config.apiBase.endsWith("/") ? "" : "/") + forecastType + queryStrings; diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js index 50c73031..3386277c 100644 --- a/modules/default/weather/weather.js +++ b/modules/default/weather/weather.js @@ -33,6 +33,7 @@ Module.register("weather", { showIndoorHumidity: false, maxNumberOfDays: 5, maxEntries: 5, + ignoreToday: false, fade: true, fadePoint: 0.25, // Start on 1/4th of the list. initialLoadDelay: 0, // 0 seconds delay @@ -48,6 +49,9 @@ Module.register("weather", { // Module properties. weatherProvider: null, + // Can be used by the provider to display location of event if nothing else is specified + firstEvent: null, + // Define required scripts. getStyles: function () { return ["font-awesome.css", "weather-icons.css", "weather.css"]; @@ -88,15 +92,13 @@ Module.register("weather", { // Override notification handler. notificationReceived: function (notification, payload, sender) { if (notification === "CALENDAR_EVENTS") { - var senderClasses = sender.data.classes.toLowerCase().split(" "); + const senderClasses = sender.data.classes.toLowerCase().split(" "); if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) { - this.firstEvent = false; - - for (var e in payload) { - var event = payload[e]; + this.firstEvent = null; + for (let event of payload) { if (event.location || event.geo) { this.firstEvent = event; - //Log.log("First upcoming event with location: ", event); + Log.debug("First upcoming event with location: ", event); break; } } @@ -114,24 +116,30 @@ Module.register("weather", { getTemplate: function () { switch (this.config.type.toLowerCase()) { case "current": - return `current.njk`; + return "current.njk"; case "hourly": - return `hourly.njk`; + return "hourly.njk"; case "daily": case "forecast": - return `forecast.njk`; + return "forecast.njk"; //Make the invalid values use the "Loading..." from forecast default: - return `forecast.njk`; + return "forecast.njk"; } }, // Add all the data to the template. getTemplateData: function () { + const forecast = this.weatherProvider.weatherForecast(); + + if (this.config.ignoreToday) { + forecast.splice(0, 1); + } + return { config: this.config, current: this.weatherProvider.currentWeather(), - forecast: this.weatherProvider.weatherForecast(), + forecast: forecast, hourly: this.weatherProvider.weatherHourly(), indoor: { humidity: this.indoorHumidity, @@ -152,7 +160,7 @@ Module.register("weather", { }, scheduleUpdate: function (delay = null) { - var nextLoad = this.config.updateInterval; + let nextLoad = this.config.updateInterval; if (delay !== null && delay >= 0) { nextLoad = delay; } @@ -176,8 +184,8 @@ Module.register("weather", { }, roundValue: function (temperature) { - var decimals = this.config.roundTemp ? 0 : 1; - var roundValue = parseFloat(temperature).toFixed(decimals); + const decimals = this.config.roundTemp ? 0 : 1; + const roundValue = parseFloat(temperature).toFixed(decimals); return roundValue === "-0" ? 0 : roundValue; }, @@ -272,8 +280,8 @@ Module.register("weather", { if (this.config.fadePoint < 0) { this.config.fadePoint = 0; } - var startingPoint = numSteps * this.config.fadePoint; - var numFadesteps = numSteps - startingPoint; + const startingPoint = numSteps * this.config.fadePoint; + const numFadesteps = numSteps - startingPoint; if (currentStep >= startingPoint) { return 1 - (currentStep - startingPoint) / numFadesteps; } else { diff --git a/modules/default/weather/weatherobject.js b/modules/default/weather/weatherobject.js index 3fbbb42a..5bd5be9a 100755 --- a/modules/default/weather/weatherobject.js +++ b/modules/default/weather/weatherobject.js @@ -28,6 +28,7 @@ class WeatherObject { this.rain = null; this.snow = null; this.precipitation = null; + this.precipitationUnits = null; this.feelsLikeTemp = null; } diff --git a/modules/default/weather/weatherprovider.js b/modules/default/weather/weatherprovider.js index 87667fd9..c193ef08 100644 --- a/modules/default/weather/weatherprovider.js +++ b/modules/default/weather/weatherprovider.js @@ -8,7 +8,7 @@ * * This class is the blueprint for a weather provider. */ -var WeatherProvider = Class.extend({ +const WeatherProvider = Class.extend({ // Weather Provider Properties providerName: null, defaults: {}, @@ -114,7 +114,7 @@ var WeatherProvider = Class.extend({ // A convenience function to make requests. It returns a promise. fetchData: function (url, method = "GET", data = null) { return new Promise(function (resolve, reject) { - var request = new XMLHttpRequest(); + const request = new XMLHttpRequest(); request.open(method, url, true); request.onreadystatechange = function () { if (this.readyState === 4) { diff --git a/modules/default/weatherforecast/weatherforecast.js b/modules/default/weatherforecast/weatherforecast.js index c180f5f5..50229262 100644 --- a/modules/default/weatherforecast/weatherforecast.js +++ b/modules/default/weatherforecast/weatherforecast.js @@ -339,7 +339,9 @@ Module.register("weatherforecast", { * * argument data object - Weather information received form openweather.org. */ - processWeather: function (data) { + processWeather: function (data, momenttz) { + let mom = momenttz ? momenttz : moment; // Exception last. + // Forcast16 (paid) API endpoint provides this data. Onecall endpoint // does not. if (data.city) { @@ -357,8 +359,8 @@ Module.register("weatherforecast", { var dayEnds = 17; if (data.city && data.city.sunrise && data.city.sunset) { - dayStarts = new Date(moment.unix(data.city.sunrise).locale("en").format("YYYY/MM/DD HH:mm:ss")).getHours(); - dayEnds = new Date(moment.unix(data.city.sunset).locale("en").format("YYYY/MM/DD HH:mm:ss")).getHours(); + dayStarts = new Date(mom.unix(data.city.sunrise).locale("en").format("YYYY/MM/DD HH:mm:ss")).getHours(); + dayEnds = new Date(mom.unix(data.city.sunset).locale("en").format("YYYY/MM/DD HH:mm:ss")).getHours(); } // Handle different structs between forecast16 and onecall endpoints @@ -379,11 +381,11 @@ Module.register("weatherforecast", { var day; var hour; if (forecast.dt_txt) { - day = moment(forecast.dt_txt, "YYYY-MM-DD hh:mm:ss").format("ddd"); - hour = new Date(moment(forecast.dt_txt).locale("en").format("YYYY-MM-DD HH:mm:ss")).getHours(); + day = mom(forecast.dt_txt, "YYYY-MM-DD hh:mm:ss").format("ddd"); + hour = new Date(mom(forecast.dt_txt).locale("en").format("YYYY-MM-DD HH:mm:ss")).getHours(); } else { - day = moment(forecast.dt, "X").format("ddd"); - hour = new Date(moment(forecast.dt, "X")).getHours(); + day = mom(forecast.dt, "X").format("ddd"); + hour = new Date(mom(forecast.dt, "X")).getHours(); } if (day !== lastDay) { @@ -392,7 +394,7 @@ Module.register("weatherforecast", { icon: this.config.iconTable[forecast.weather[0].icon], maxTemp: this.roundValue(forecast.temp.max), minTemp: this.roundValue(forecast.temp.min), - rain: this.processRain(forecast, forecastList) + rain: this.processRain(forecast, forecastList, mom) }; this.forecast.push(forecastData); lastDay = day; @@ -482,16 +484,18 @@ Module.register("weatherforecast", { * That object has a property "3h" which contains the amount of rain since the previous forecast in the list. * This code finds all forecasts that is for the same day and sums the amount of rain and returns that. */ - processRain: function (forecast, allForecasts) { + processRain: function (forecast, allForecasts, momenttz) { + let mom = momenttz ? momenttz : moment; // Exception last. + //If the amount of rain actually is a number, return it if (!isNaN(forecast.rain)) { return forecast.rain; } //Find all forecasts that is for the same day - var checkDateTime = forecast.dt_txt ? moment(forecast.dt_txt, "YYYY-MM-DD hh:mm:ss") : moment(forecast.dt, "X"); + var checkDateTime = forecast.dt_txt ? mom(forecast.dt_txt, "YYYY-MM-DD hh:mm:ss") : mom(forecast.dt, "X"); var daysForecasts = allForecasts.filter(function (item) { - var itemDateTime = item.dt_txt ? moment(item.dt_txt, "YYYY-MM-DD hh:mm:ss") : moment(item.dt, "X"); + var itemDateTime = item.dt_txt ? mom(item.dt_txt, "YYYY-MM-DD hh:mm:ss") : mom(item.dt, "X"); return itemDateTime.isSame(checkDateTime, "day") && item.rain instanceof Object; }); diff --git a/package-lock.json b/package-lock.json index b84201cc..25432f9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "magicmirror", - "version": "2.15.0", + "version": "2.16.0-develop", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -13,42 +13,41 @@ } }, "@babel/compat-data": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.8.tgz", - "integrity": "sha512-EaI33z19T4qN3xLXsGf48M2cDqa6ei9tPZlfLdb2HC+e/cFtREiRd8hdSqDbwdLB0/+gLwqJmCYASH0z2bUdog==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz", + "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==", "dev": true }, "@babel/core": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.8.tgz", - "integrity": "sha512-oYapIySGw1zGhEFRd6lzWNLWFX2s5dA/jm+Pw/+59ZdXtjyIuwlXbrId22Md0rgZVop+aVoqow2riXhBLNyuQg==", + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.6.tgz", + "integrity": "sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helpers": "^7.13.0", - "@babel/parser": "^7.13.4", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0", + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.5", + "@babel/helper-compilation-targets": "^7.14.5", + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helpers": "^7.14.6", + "@babel/parser": "^7.14.6", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", - "lodash": "^4.17.19", "semver": "^6.3.0", "source-map": "^0.5.0" }, "dependencies": { "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", "dev": true, "requires": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.14.5" } }, "source-map": { @@ -60,12 +59,12 @@ } }, "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz", + "integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==", "dev": true, "requires": { - "@babel/types": "^7.13.0", + "@babel/types": "^7.14.5", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -79,139 +78,153 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.8.tgz", - "integrity": "sha512-pBljUGC1y3xKLn1nrx2eAhurLMA8OqBtBP/JwG4U8skN7kf8/aqwwxpV1N6T0e7r6+7uNitIa/fUxPFagSXp3A==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", + "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", "dev": true, "requires": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", + "@babel/compat-data": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", "semver": "^6.3.0" } }, "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", + "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-get-function-arity": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", + "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", + "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz", - "integrity": "sha512-yvRf8Ivk62JwisqV1rFRMxiSMDGnN6KH1/mDMmIrij4jztpQNRoHqqMG3U6apYbGRPJpgPalhva9Yd06HlUxJQ==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz", + "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==", "dev": true, "requires": { - "@babel/types": "^7.13.0" + "@babel/types": "^7.14.5" } }, "@babel/helper-module-imports": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz", - "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", + "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.14.5" } }, "@babel/helper-module-transforms": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.0.tgz", - "integrity": "sha512-Ls8/VBwH577+pw7Ku1QkUWIyRRNHpYlts7+qSqBBFCW3I8QteB9DxfcZ5YJpOwH6Ihe/wn8ch7fMGOP1OhEIvw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.5.tgz", + "integrity": "sha512-iXpX4KW8LVODuAieD7MzhNjmM6dzYY5tfRqT+R9HDXWl0jPn/djKmA+G9s/2C2T9zggw5tK1QNqZ70USfedOwA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-simple-access": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.12.11", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0", - "lodash": "^4.17.19" + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-simple-access": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", - "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", + "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.14.5" } }, + "@babel/helper-plugin-utils": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "dev": true + }, "@babel/helper-replace-supers": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.0.tgz", - "integrity": "sha512-Segd5me1+Pz+rmN/NFBOplMbZG3SqRJOBlY+mA0SxAv6rjj7zJqr1AVr3SfzUVTLCv7ZLU5FycOM/SBGuLPbZw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", + "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.13.0", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" + "@babel/helper-member-expression-to-functions": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/helper-simple-access": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz", - "integrity": "sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz", + "integrity": "sha512-nfBN9xvmCt6nrMZjfhkl7i0oTV3yxR4/FztsbOASyTvVcoYd0TRHh7eMLdlEcCqobydC0LAF3LtC92Iwxo0wyw==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.14.5" } }, "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", + "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.14.5" } }, "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==" + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==" }, "@babel/helper-validator-option": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", - "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", "dev": true }, "@babel/helpers": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.0.tgz", - "integrity": "sha512-aan1MeFPxFacZeSz6Ld7YZo5aPuqnKlD7+HZY75xQsueczFccP9A7V05+oe0XpLwHK3oLorPe9eaAUljL7WEaQ==", + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz", + "integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==", "dev": true, "requires": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" } }, "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "requires": { - "@babel/helper-validator-identifier": "^7.12.11", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -268,57 +281,174 @@ } }, "@babel/parser": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", - "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz", + "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==", "dev": true }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/template": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", + "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" }, "dependencies": { "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", "dev": true, "requires": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.14.5" } } } }, "@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.7.tgz", + "integrity": "sha512-9vDr5NzHu27wgwejuKL7kIOm4bwEtaPQ4Z6cpCmjSuaRqpH/7xc4qcGEscwMqlkwgcXl6MvqoAjZkQ24uSdIZQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.14.7", + "@babel/types": "^7.14.5", "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "globals": "^11.1.0" }, "dependencies": { "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", "dev": true, "requires": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.14.5" } }, "globals": { @@ -330,16 +460,21 @@ } }, "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", + "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", + "@babel/helper-validator-identifier": "^7.14.5", "to-fast-properties": "^2.0.0" } }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, "@electron/get": { "version": "1.12.4", "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.12.4.tgz", @@ -356,35 +491,31 @@ "sumchecker": "^3.0.1" } }, + "@es-joy/jsdoccomment": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.8.0.tgz", + "integrity": "sha512-Xd3GzYsL2sz2pcdtYt5Q0Wz1ol/o9Nt2UQL4nFPDcaEomvPmwjJsbjkKx1SKhl2h3TgwazNBLdcNr2m0UiGiFA==", + "dev": true, + "requires": { + "comment-parser": "^1.1.5", + "esquery": "^1.4.0", + "jsdoc-type-pratt-parser": "1.0.4" + } + }, "@eslint/eslintrc": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", - "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", + "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", "requires": { "ajv": "^6.12.4", "debug": "^4.1.1", "espree": "^7.3.0", - "globals": "^12.1.0", + "globals": "^13.9.0", "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "requires": { - "type-fest": "^0.8.1" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" - } } }, "@istanbuljs/load-nyc-config": { @@ -400,49 +531,6 @@ "resolve-from": "^5.0.0" }, "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -457,6 +545,197 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, + "@jest/console": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.0.2.tgz", + "integrity": "sha512-/zYigssuHLImGeMAACkjI4VLAiiJznHgAl3xnFT19iWyct2LhrH3KXOjHRmxBGTkiPLZKKAJAgaPpiU9EZ9K+w==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.0.2", + "jest-util": "^27.0.2", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.0.5.tgz", + "integrity": "sha512-g73//jF0VwsOIrWUC9Cqg03lU3QoAMFxVjsm6n6yNmwZcQPN/o8w+gLWODw5VfKNFZT38otXHWxc6b8eGDUpEA==", + "dev": true, + "requires": { + "@jest/console": "^27.0.2", + "@jest/reporters": "^27.0.5", + "@jest/test-result": "^27.0.2", + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^27.0.2", + "jest-config": "^27.0.5", + "jest-haste-map": "^27.0.5", + "jest-message-util": "^27.0.2", + "jest-regex-util": "^27.0.1", + "jest-resolve": "^27.0.5", + "jest-resolve-dependencies": "^27.0.5", + "jest-runner": "^27.0.5", + "jest-runtime": "^27.0.5", + "jest-snapshot": "^27.0.5", + "jest-util": "^27.0.2", + "jest-validate": "^27.0.2", + "jest-watcher": "^27.0.2", + "micromatch": "^4.0.4", + "p-each-series": "^2.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.0.5.tgz", + "integrity": "sha512-IAkJPOT7bqn0GiX5LPio6/e1YpcmLbrd8O5EFYpAOZ6V+9xJDsXjdgN2vgv9WOKIs/uA1kf5WeD96HhlBYO+FA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/node": "*", + "jest-mock": "^27.0.3" + } + }, + "@jest/fake-timers": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.0.5.tgz", + "integrity": "sha512-d6Tyf7iDoKqeUdwUKrOBV/GvEZRF67m7lpuWI0+SCD9D3aaejiOQZxAOxwH2EH/W18gnfYaBPLi0VeTGBHtQBg==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "@sinonjs/fake-timers": "^7.0.2", + "@types/node": "*", + "jest-message-util": "^27.0.2", + "jest-mock": "^27.0.3", + "jest-util": "^27.0.2" + } + }, + "@jest/globals": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.0.5.tgz", + "integrity": "sha512-qqKyjDXUaZwDuccpbMMKCCMBftvrbXzigtIsikAH/9ca+kaae8InP2MDf+Y/PdCSMuAsSpHS6q6M25irBBUh+Q==", + "dev": true, + "requires": { + "@jest/environment": "^27.0.5", + "@jest/types": "^27.0.2", + "expect": "^27.0.2" + } + }, + "@jest/reporters": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.0.5.tgz", + "integrity": "sha512-4uNg5+0eIfRafnpgu3jCZws3NNcFzhu5JdRd1mKQ4/53+vkIqwB6vfZ4gn5BdGqOaLtYhlOsPaL5ATkKzyBrJw==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.0.2", + "@jest/test-result": "^27.0.2", + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^27.0.5", + "jest-resolve": "^27.0.5", + "jest-util": "^27.0.2", + "jest-worker": "^27.0.2", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.0.0" + } + }, + "@jest/source-map": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.1.tgz", + "integrity": "sha512-yMgkF0f+6WJtDMdDYNavmqvbHtiSpwRN2U/W+6uztgfqgkq/PXdKPqjBTUF1RD/feth4rH5N3NW0T5+wIuln1A==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.0.2.tgz", + "integrity": "sha512-gcdWwL3yP5VaIadzwQtbZyZMgpmes8ryBAJp70tuxghiA8qL4imJyZex+i+USQH2H4jeLVVszhwntgdQ97fccA==", + "dev": true, + "requires": { + "@jest/console": "^27.0.2", + "@jest/types": "^27.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.0.5.tgz", + "integrity": "sha512-opztnGs+cXzZ5txFG2+omBaV5ge/0yuJNKbhE3DREMiXE0YxBuzyEa6pNv3kk2JuucIlH2Xvgmn9kEEHSNt/SA==", + "dev": true, + "requires": { + "@jest/test-result": "^27.0.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.0.5", + "jest-runtime": "^27.0.5" + } + }, + "@jest/transform": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.0.5.tgz", + "integrity": "sha512-lBD6OwKXSc6JJECBNk4mVxtSVuJSBsQrJ9WCBisfJs7EZuYq4K6vM9HmoB7hmPiLIDGeyaerw3feBV/bC4z8tg==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.0.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.0.5", + "jest-regex-util": "^27.0.1", + "jest-util": "^27.0.2", + "micromatch": "^4.0.4", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } + }, + "@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, "@kwsites/file-exists": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", @@ -471,28 +750,28 @@ "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" }, "@nodelib/fs.scandir": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", - "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "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": { - "@nodelib/fs.stat": "2.0.4", + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "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 }, "@nodelib/fs.walk": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", - "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", + "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.4", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, @@ -502,27 +781,27 @@ "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" }, "@sinonjs/commons": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", - "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" } }, "@sinonjs/samsam": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz", - "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.0.2.tgz", + "integrity": "sha512-jxPRPp9n93ci7b8hMfJOFDPRLFYadN6FSpeROFTR4UNF4i5b+EK6m4QXPO46BDhFgRy1JuS87zAnFOzCUwMJcQ==", "dev": true, "requires": { "@sinonjs/commons": "^1.6.0", @@ -563,6 +842,53 @@ "defer-to-connect": "^1.0.1" } }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.14", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", + "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", + "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, "@types/cacheable-request": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", @@ -590,12 +916,51 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/http-cache-semantics": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==", "dev": true }, + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, "@types/keyv": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", @@ -615,9 +980,9 @@ } }, "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", "dev": true }, "@types/minimist": { @@ -627,9 +992,9 @@ "dev": true }, "@types/node": { - "version": "12.20.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.4.tgz", - "integrity": "sha512-xRCgeE0Q4pT5UZ189TJ3SpYuX/QGl6QIAOAIeDSbAVAd2gX1NxSZup4jNVK7cxIeP8KDSbJgcckun495isP1jQ==" + "version": "12.20.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.15.tgz", + "integrity": "sha512-F6S4Chv4JicJmyrwlDkxUdGNSplsQdGwp1A0AJloEVDirWdZOAiRHhovDlsFkKUrquUXhz1imJhXHsf59auyAg==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -643,6 +1008,12 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/prettier": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.0.tgz", + "integrity": "sha512-hkc1DATxFLQo4VxPDpMH1gCkPpBbpOoJ/4nhuXw4n63/0R6bCpQECj4+K226UJ4JO/eJQz+1mC2I7JsWanAdQw==", + "dev": true + }, "@types/puppeteer": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.3.tgz", @@ -670,6 +1041,12 @@ "@types/node": "*" } }, + "@types/stack-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", + "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", + "dev": true + }, "@types/unist": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", @@ -682,6 +1059,21 @@ "integrity": "sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==", "dev": true }, + "@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "dev": true + }, "@types/yauzl": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", @@ -692,12 +1084,83 @@ "@types/node": "*" } }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "@typescript-eslint/experimental-utils": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.0.tgz", + "integrity": "sha512-9XD9s7mt3QWMk82GoyUpc/Ji03vz4T5AYlHF9DcoFNfJ/y3UAclRsfGiE2gLfXtyC+JRA3trR7cR296TEb1oiQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.28.0", + "@typescript-eslint/types": "4.28.0", + "@typescript-eslint/typescript-estree": "4.28.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + } + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.0.tgz", + "integrity": "sha512-eCALCeScs5P/EYjwo6se9bdjtrh8ByWjtHzOkC4Tia6QQWtQr3PHovxh3TdYTuFcurkYI4rmFsRFpucADIkseg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.0", + "@typescript-eslint/visitor-keys": "4.28.0" + } + }, + "@typescript-eslint/types": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.0.tgz", + "integrity": "sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA==", "dev": true }, + "@typescript-eslint/typescript-estree": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz", + "integrity": "sha512-m19UQTRtxMzKAm8QxfKpvh6OwQSXaW1CdZPoCaQuLwAq7VZMNuhJmZR4g5281s2ECt658sldnJfdpSZZaxUGMQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.0", + "@typescript-eslint/visitor-keys": "4.28.0", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz", + "integrity": "sha512-PjJyTWwrlrvM5jazxYF5ZPs/nl0kHDZMVbuIcbpawVXaDPelp3+S9zpOz5RmVUfS/fD5l5+ZXNKnWhNYjPzCvw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.0", + "eslint-visitor-keys": "^2.0.0" + } + }, "@wdio/config": { "version": "6.12.1", "resolved": "https://registry.npmjs.org/@wdio/config/-/config-6.12.1.tgz", @@ -787,10 +1250,13 @@ "dev": true }, "agent-base": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", - "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", - "dev": true + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } }, "aggregate-error": { "version": "3.1.0", @@ -818,6 +1284,23 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" }, + "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": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "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 + } + } + }, "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", @@ -832,9 +1315,9 @@ } }, "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -851,9 +1334,9 @@ } }, "archiver": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.2.0.tgz", - "integrity": "sha512-QEAKlgQuAtUxKeZB9w5/ggKXh21bZS+dzzuQ0RPBC20qtDCbTyzqmisoeJP46MP39fg4B4IcyvR+yeyEBdblsQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.0.tgz", + "integrity": "sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==", "dev": true, "requires": { "archiver-utils": "^2.1.0", @@ -861,8 +1344,8 @@ "buffer-crc32": "^0.2.1", "readable-stream": "^3.6.0", "readdir-glob": "^1.0.0", - "tar-stream": "^2.1.4", - "zip-stream": "^4.0.4" + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" }, "dependencies": { "readable-stream": { @@ -944,6 +1427,7 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, "requires": { "safer-buffer": "~2.1.0" } @@ -951,12 +1435,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, "astral-regex": { @@ -973,7 +1452,8 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true }, "at-least-node": { "version": "1.0.0", @@ -1005,12 +1485,85 @@ "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=" + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true }, "aws4": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "babel-jest": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.0.5.tgz", + "integrity": "sha512-bTMAbpCX7ldtfbca2llYLeSFsDM257aspyAOpsdrdSrBqoLkWCy4HPYTXtXWaSLgFPjrJGACL65rzzr4RFGadw==", + "dev": true, + "requires": { + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^27.0.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.1.tgz", + "integrity": "sha512-sqBF0owAcCDBVEDtxqfYr2F36eSHdx7lAVGyYuOBRnKdD6gzcy0I0XrAYCZgOA3CRrLhmR+Uae9nogPzmAtOfQ==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.0.1.tgz", + "integrity": "sha512-nIBIqCEpuiyhvjQs2mVNwTxQQa2xk70p9Dd/0obQGBf8FBzbnI8QhQKzLsWMN2i6q+5B0OcWDtrboBX5gmOLyA==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^27.0.1", + "babel-preset-current-node-syntax": "^1.0.0" + } }, "bail": { "version": "1.0.5", @@ -1019,9 +1572,9 @@ "dev": true }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base-64": { "version": "0.1.0", @@ -1057,16 +1610,11 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, "requires": { "tweetnacl": "^0.14.3" } }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -1132,9 +1680,9 @@ } }, "boolean": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.2.tgz", - "integrity": "sha512-RwywHlpCRc3/Wh81MiCKun4ydaIFyW5Ea6JbL6sRCVx5q5irDw7pMXBUFYF/jArQ6YrG36q0kpovc9P/Kd3I4g==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.2.tgz", + "integrity": "sha512-YN6UmV0FfLlBVvRvNPx3pz5W/mUoYB24J4WSXOKP/OOJpi+Oq6WYqPaNTHzjI0QzwWtnvEd5CGYyQPgp1jFxnw==", "optional": true }, "brace-expansion": { @@ -1161,23 +1709,26 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, "browserslist": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.3.tgz", - "integrity": "sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==", + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001181", - "colorette": "^1.2.1", - "electron-to-chromium": "^1.3.649", + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", "escalade": "^3.1.1", - "node-releases": "^1.1.70" + "node-releases": "^1.1.71" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" } }, "buffer": { @@ -1198,8 +1749,7 @@ "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==", - "optional": true + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "bytes": { "version": "3.1.0", @@ -1259,9 +1809,9 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, "camelcase-keys": { @@ -1275,12 +1825,6 @@ "quick-lru": "^4.0.1" }, "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, "quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", @@ -1290,48 +1834,32 @@ } }, "caniuse-lite": { - "version": "1.0.30001196", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001196.tgz", - "integrity": "sha512-CPvObjD3ovWrNBaXlAIGWmg2gQQuJ5YhuciUOjPRox6hIQttu8O+b51dx6VIpIY9ESd2d0Vac1RKpICdG4rGUg==", + "version": "1.0.30001239", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001239.tgz", + "integrity": "sha512-cyBkXJDMeI4wthy8xJ2FvDU6+0dtcZSJW3voUF8+e9f1bBeuvyZfc3PNbkOETyhbR+dGCPzn9E7MA3iwzusOhQ==", "dev": true }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "chai": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", - "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - } - }, - "chai-as-promised": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", - "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", - "dev": true, - "requires": { - "check-error": "^1.0.2" - } + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, "character-entities": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", @@ -1350,27 +1878,10 @@ "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", "dev": true }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true - }, - "chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", - "dev": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.3.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - } + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" }, "chownr": { "version": "1.1.4", @@ -1401,9 +1912,15 @@ } }, "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.1.tgz", + "integrity": "sha512-jVamGdJPDeuQilKhvVn1h3knuMOZzr8QDnpk+M9aMlCaMkTDd6fBWPhiDqFvFZ07pL0liqabAiuy8SY4jGHeaw==", "dev": true }, "clarinet": { @@ -1445,6 +1962,18 @@ "mimic-response": "^1.0.0" } }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1473,14 +2002,15 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "requires": { "delayed-stream": "~1.0.0" } }, "comment-parser": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.1.2.tgz", - "integrity": "sha512-AOdq0i8ghZudnYv8RUnHrhTgafUGs61Rdz9jemU5x2lnZwAWyOq7vySo626K59e1fVKH1xSRorJwPVRLSWOoAQ==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.1.5.tgz", + "integrity": "sha512-RePCE4leIhBlmrqiYTvaqEeGYg7qpSl4etaIabKtdOQVi+mSTIBBklGUwIr79GXYnl3LpMwmDw4KeR2stNc6FA==", "dev": true }, "commondir": { @@ -1489,25 +2019,19 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, - "compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", - "dev": true - }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "compress-commons": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.0.tgz", - "integrity": "sha512-ofaaLqfraD1YRTkrRKPCrGJ1pFeDG/MVCkVVV2FNGeWquSlqw5wOrwOfPQ1xF2u+blpeWASie5EubHz+vsNIgA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", + "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", "dev": true, "requires": { "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.1", + "crc32-stream": "^4.0.2", "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" }, @@ -1543,9 +2067,9 @@ } }, "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", "optional": true, "requires": { "ini": "^1.3.4", @@ -1553,12 +2077,12 @@ } }, "console-stamp": { - "version": "3.0.0-rc4.3", - "resolved": "https://registry.npmjs.org/console-stamp/-/console-stamp-3.0.0-rc4.3.tgz", - "integrity": "sha512-NE9IGO0q+gVReZqX+ArFZOKCVPIOIef6huPNxlvsjYahHL9rVYuBUBkK0hLOlW90jH2Y2yo/Ubm2vDNym37WBw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/console-stamp/-/console-stamp-3.0.2.tgz", + "integrity": "sha512-nYIxVrp1Cau8wRy8RQJO1VNBTYQPnFcN7SrsLAStSavo38Y4+jcysh5n4nZNd/WkR2IOULgwr2+6qDxMUA7Hog==", "requires": { "chalk": "^4.1.0", - "dateformat": "^4.0.0" + "dateformat": "^4.5.1" } }, "content-disposition": { @@ -1575,9 +2099,9 @@ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "dev": true, "requires": { "safe-buffer": "~5.1.1" @@ -1594,9 +2118,9 @@ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "core-js": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.9.1.tgz", - "integrity": "sha512-gSjRvzkxQc1zjM/5paAmL4idJBFzuJoo+jDjF1tStYFMV2ERfD02HhahhCGXUyHxQRG4yFKVSdO6g62eoRMcDg==", + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.15.1.tgz", + "integrity": "sha512-h8VbZYnc9pDzueiS2610IULDkpFFPunHwIpl8yRwFahAEEdSpHlTy3h3z3rKq5h11CaUdBEeRViu9AYvbxiMeg==", "optional": true }, "core-util-is": { @@ -1669,10 +2193,10 @@ "which": "^2.0.1" } }, - "crypto-js": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", - "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" }, "css-shorthand-properties": { "version": "1.1.1", @@ -1719,6 +2243,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -1748,9 +2273,9 @@ } }, "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "decamelize-keys": { @@ -1763,12 +2288,6 @@ "map-obj": "^1.0.0" }, "dependencies": { - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", @@ -1778,9 +2297,9 @@ } }, "decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.0.tgz", + "integrity": "sha512-MrQRs2gyD//7NeHi9TtsfClkf+cFAewDz+PZHR8ILKglLmBMyVX3ymQ+oeznE3tjrS7beTN+6JXb2C3JDHm7ug==", "dev": true }, "decompress-response": { @@ -1791,14 +2310,11 @@ "mimic-response": "^1.0.0" } }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true }, "deep-is": { "version": "0.1.3", @@ -1837,7 +2353,8 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true }, "depd": { "version": "1.1.2", @@ -1849,10 +2366,16 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, "detect-node": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", - "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "optional": true }, "dev-null": { @@ -1890,13 +2413,19 @@ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, + "diff-sequences": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.1.tgz", + "integrity": "sha512-XPLijkfJUh/PIBnfkcSHgvD6tlYixmcMAn3osTk6jt+H0v/mgURto1XUiD9DKuGX5NDoVS6dSlA23gd9FUaCFg==", + "dev": true + }, "digest-fetch": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.1.6.tgz", - "integrity": "sha512-CFNX4+TkxecH2L2bw6tI9RAJ7xQuE3j/fDxZe6HOyazR5lhGhF76Pxhb0/Lam3vtGsZPop3RMXydWsNZ//TJwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.2.0.tgz", + "integrity": "sha512-DSbWN+dPXH+9A/aqmGnpI40cVKzJRgL4iDm1eGpsZ1MpW3tXQuBJN5xNY3PEqUx3QjkQIPyD99ypClHr9fW9Ow==", "requires": { "base-64": "^0.1.0", - "crypto-js": "^3.1.9-1" + "md5": "^2.3.0" } }, "dir-glob": { @@ -1927,9 +2456,9 @@ }, "dependencies": { "domelementtype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", - "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", "dev": true }, "entities": { @@ -1991,6 +2520,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -2012,9 +2542,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-11.3.0.tgz", - "integrity": "sha512-MhdS0gok3wZBTscLBbYrOhLaQybCSAfkupazbK1dMP5c+84eVMxJE/QGohiWQkzs0tVFIJsAHyN19YKPbelNrQ==", + "version": "11.4.9", + "resolved": "https://registry.npmjs.org/electron/-/electron-11.4.9.tgz", + "integrity": "sha512-3TJG1vAnuR8p47mzorCW5l7uWCjdNUufIbZ+gKjm010dtHmhrO1zchP1a76vuT4BllK8q1iygFSkNnDlZ0i2pA==", "optional": true, "requires": { "@electron/get": "^1.0.1", @@ -2056,9 +2586,15 @@ } }, "electron-to-chromium": { - "version": "1.3.681", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.681.tgz", - "integrity": "sha512-W6uYvSUTHuyX2DZklIESAqx57jfmGjUkd7Z3RWqLdj9Mmt39ylhBuvFXlskQnvBHj0MYXIeQI+mjiwVddZLSvA==", + "version": "1.3.756", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.756.tgz", + "integrity": "sha512-WsmJym1TMeHVndjPjczTFbnRR/c4sbzg8fBFtuhlb2Sru3i/S1VGpzDSrv/It8ctMU2bj8G7g7/O3FzYMGw6eA==", + "dev": true + }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", "dev": true }, "emoji-regex": { @@ -2080,9 +2616,9 @@ } }, "engine.io": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-5.0.0.tgz", - "integrity": "sha512-BATIdDV3H1SrE9/u2BAotvsmjJg0t1P4+vGedImSs1lkFAtQdvk4Ev1y4LDiPF7BPWgXWEG+NDY+nLvW3UrMWw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-5.1.1.tgz", + "integrity": "sha512-aMWot7H5aC8L4/T8qMYbLdvKlZOdJTH54FxfdFunTGvhMx1BHkJOntWArsVfgAZVwAO9LC2sryPWRcEeUzCe5w==", "requires": { "accepts": "~1.3.4", "base64id": "2.0.0", @@ -2123,9 +2659,9 @@ "dev": true }, "env-paths": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", - "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==" + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==" }, "error-ex": { "version": "1.3.2", @@ -2218,27 +2754,29 @@ } }, "eslint": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.23.0.tgz", - "integrity": "sha512-kqvNVbdkjzpFy0XOszNwjkKzZ+6TcwCQ/h+ozlcIWwaimBBuhlQ4nN6kbiM2L+OjDcznkTJxzYfRFH92sx4a0Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.29.0.tgz", + "integrity": "sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==", "requires": { "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.0", + "@eslint/eslintrc": "^0.4.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.0.1", "doctrine": "^3.0.0", "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", "eslint-scope": "^5.1.1", "eslint-utils": "^2.1.0", "eslint-visitor-keys": "^2.0.0", "espree": "^7.3.1", "esquery": "^1.4.0", "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", + "glob-parent": "^5.1.2", "globals": "^13.6.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", @@ -2247,7 +2785,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.21", + "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -2256,7 +2794,7 @@ "semver": "^7.2.1", "strip-ansi": "^6.0.0", "strip-json-comments": "^3.1.0", - "table": "^6.0.4", + "table": "^6.0.9", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -2272,30 +2810,41 @@ } }, "eslint-config-prettier": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz", - "integrity": "sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", "dev": true }, - "eslint-plugin-jsdoc": { - "version": "32.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-32.3.0.tgz", - "integrity": "sha512-zyx7kajDK+tqS1bHuY5sapkad8P8KT0vdd/lE55j47VPG2MeenSYuIY/M/Pvmzq5g0+3JB+P3BJGUXmHxtuKPQ==", + "eslint-plugin-jest": { + "version": "24.3.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.3.6.tgz", + "integrity": "sha512-WOVH4TIaBLIeCX576rLcOgjNXqP+jNlCiEmRgFTfQtJ52DpwnIQKAVGlGPAN7CZ33bW6eNfHD6s8ZbEUTQubJg==", "dev": true, "requires": { - "comment-parser": "1.1.2", + "@typescript-eslint/experimental-utils": "^4.0.1" + } + }, + "eslint-plugin-jsdoc": { + "version": "35.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-35.4.0.tgz", + "integrity": "sha512-0cr+NkPTxpTiMCtYOd8W5fd2IyC/CmaTHKb+0bzkpP9p8HfmJ3B2/M6FWj97rQJOLwLMkx+g2MIEZsrttpbFmQ==", + "dev": true, + "requires": { + "@es-joy/jsdoccomment": "^0.8.0-alpha.2", + "comment-parser": "1.1.5", "debug": "^4.3.1", - "jsdoctypeparser": "^9.0.0", - "lodash": "^4.17.20", - "regextras": "^0.7.1", - "semver": "^7.3.4", + "esquery": "^1.4.0", + "jsdoc-type-pratt-parser": "^1.0.4", + "lodash": "^4.17.21", + "regextras": "^0.8.0", + "semver": "^7.3.5", "spdx-expression-parse": "^3.0.1" }, "dependencies": { "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -2304,9 +2853,9 @@ } }, "eslint-plugin-prettier": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz", - "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", + "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" @@ -2337,9 +2886,9 @@ } }, "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" }, "espree": { "version": "7.3.1", @@ -2409,30 +2958,27 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" }, "dependencies": { "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true } } }, @@ -2445,12 +2991,40 @@ "clone-regexp": "^2.1.0" } }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, "exit-on-epipe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", "dev": true }, + "expect": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.0.2.tgz", + "integrity": "sha512-YJFNJe2+P2DqH+ZrXy+ydRQYO87oxRUonZImpDodR1G7qo3NYd3pL+NQ9Keqpez3cehczYwZDBC3A7xk3n7M/w==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.0.1", + "jest-matcher-utils": "^27.0.2", + "jest-message-util": "^27.0.2", + "jest-regex-util": "^27.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -2513,9 +3087,9 @@ } }, "express-ipfilter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/express-ipfilter/-/express-ipfilter-1.1.2.tgz", - "integrity": "sha512-dm1G3sVxlSbcOWSxfUTCo20ySyNQXJ4hJD5fuQJFoZlhkQvpbuDGBlh8AbFm1GwX85EWvfyhekOkvcydaXkBkg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/express-ipfilter/-/express-ipfilter-1.2.0.tgz", + "integrity": "sha512-nPXKMuhqVjX7+Vny4XsrpdqlX4YAGcanE0gh5xzpfmNTsINGAgPnpk67kb0No3p1m4vGQQLU6hdaXRxsuGNlTA==", "requires": { "ip": "~1.1.0", "lodash": "^4.17.11", @@ -2526,7 +3100,8 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true }, "extract-zip": { "version": "1.7.0", @@ -2560,7 +3135,8 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true }, "fast-deep-equal": { "version": "3.1.3", @@ -2612,6 +3188,15 @@ "reusify": "^1.0.4" } }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -2684,81 +3269,18 @@ "commondir": "^1.0.1", "make-dir": "^3.0.2", "pkg-dir": "^4.1.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - } } }, "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==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { - "locate-path": "^6.0.0", + "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, - "find-versions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", - "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", - "dev": true, - "requires": { - "semver-regex": "^3.1.2" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -2786,22 +3308,24 @@ "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true }, "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, "requires": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" }, "fresh": { "version": "0.5.2", @@ -2865,12 +3389,6 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true - }, "get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -2901,14 +3419,15 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2919,17 +3438,17 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "requires": { "is-glob": "^4.0.1" } }, "global-agent": { - "version": "2.1.12", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.12.tgz", - "integrity": "sha512-caAljRMS/qcDo69X9BfkgrihGUgGx44Fb4QQToNQjsiWh+YlQ66uqYVAdA8Olqit+5Ng0nkz09je3ZzANMZcjg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.2.0.tgz", + "integrity": "sha512-+20KpaW6DDLqhG7JDiJpD1JvNvb8ts+TNl7BPOYcURqCrXqnN1Vf+XVOrkKJAFPqfX+oEhsdzOj1hLWkBTdNJg==", "optional": true, "requires": { "boolean": "^3.0.1", @@ -2942,9 +3461,9 @@ }, "dependencies": { "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "optional": true, "requires": { "lru-cache": "^6.0.0" @@ -2996,9 +3515,9 @@ } }, "globals": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz", - "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==", + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", "requires": { "type-fest": "^0.20.2" }, @@ -3020,9 +3539,9 @@ } }, "globby": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", - "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", "dev": true, "requires": { "array-union": "^2.1.0", @@ -3085,21 +3604,17 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true }, "har-validator": { "version": "5.1.5", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, "requires": { "ajv": "^6.12.3", "har-schema": "^2.0.0" @@ -3143,21 +3658,15 @@ } } }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, "helmet": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.4.1.tgz", - "integrity": "sha512-G8tp0wUMI7i8wkMk2xLcEvESg5PiCitFMYgGRc/PwULB0RVhTP5GFdxOwvJwp9XVha8CuS8mnhmE8I/8dx/pbw==" + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.6.0.tgz", + "integrity": "sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==" }, "hosted-git-info": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.0.tgz", - "integrity": "sha512-fqhGdjk4av7mT9fU/B01dUtZ+WZSc/XEXMoLXDVZukiQRXxeHSSz3AqbeWRJHtF8EQYHlAgB1NSAHU0Cm7aqZA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -3235,10 +3744,22 @@ } } }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -3256,43 +3777,31 @@ } }, "https-proxy-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", - "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", "dev": true, "requires": { - "agent-base": "5", + "agent-base": "6", "debug": "4" } }, "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "husky": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz", - "integrity": "sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "ci-info": "^2.0.0", - "compare-versions": "^3.6.0", - "cosmiconfig": "^7.0.0", - "find-versions": "^4.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^5.0.0", - "please-upgrade-node": "^3.2.0", - "slash": "^3.0.0", - "which-pm-runs": "^1.0.0" - } + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz", + "integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==", + "dev": true }, "iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } @@ -3323,6 +3832,16 @@ "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", "dev": true }, + "import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3334,12 +3853,6 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3396,25 +3909,24 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", "dev": true, "requires": { - "binary-extensions": "^2.0.0" + "ci-info": "^3.1.1" } }, - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true - }, "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", "dev": true, "requires": { "has": "^1.0.3" @@ -3427,9 +3939,9 @@ "dev": true }, "is-docker": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", - "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true }, "is-extglob": { @@ -3442,6 +3954,12 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -3469,9 +3987,9 @@ "dev": true }, "is-potential-custom-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", - "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "is-regexp": { @@ -3489,7 +4007,14 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "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 }, "is-windows": { "version": "1.0.2", @@ -3519,7 +4044,8 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true }, "istanbul-lib-coverage": { "version": "3.0.0", @@ -3603,6 +4129,512 @@ "istanbul-lib-report": "^3.0.0" } }, + "jest": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.5.tgz", + "integrity": "sha512-4NlVMS29gE+JOZvgmSAsz3eOjkSsHqjTajlIsah/4MVSmKvf3zFP/TvgcLoWe2UVHiE9KF741sReqhF0p4mqbQ==", + "dev": true, + "requires": { + "@jest/core": "^27.0.5", + "import-local": "^3.0.2", + "jest-cli": "^27.0.5" + }, + "dependencies": { + "jest-cli": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.0.5.tgz", + "integrity": "sha512-kZqY020QFOFQKVE2knFHirTBElw3/Q0kUbDc3nMfy/x+RQ7zUY89SUuzpHHJoSX1kX7Lq569ncvjNqU3Td/FCA==", + "dev": true, + "requires": { + "@jest/core": "^27.0.5", + "@jest/test-result": "^27.0.2", + "@jest/types": "^27.0.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "jest-config": "^27.0.5", + "jest-util": "^27.0.2", + "jest-validate": "^27.0.2", + "prompts": "^2.0.1", + "yargs": "^16.0.3" + } + } + } + }, + "jest-changed-files": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.0.2.tgz", + "integrity": "sha512-eMeb1Pn7w7x3wue5/vF73LPCJ7DKQuC9wQUR5ebP9hDPpk5hzcT/3Hmz3Q5BOFpR3tgbmaWhJcMTVgC8Z1NuMw==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "jest-circus": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.0.5.tgz", + "integrity": "sha512-p5rO90o1RTh8LPOG6l0Fc9qgp5YGv+8M5CFixhMh7gGHtGSobD1AxX9cjFZujILgY8t30QZ7WVvxlnuG31r8TA==", + "dev": true, + "requires": { + "@jest/environment": "^27.0.5", + "@jest/test-result": "^27.0.2", + "@jest/types": "^27.0.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.0.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.0.2", + "jest-matcher-utils": "^27.0.2", + "jest-message-util": "^27.0.2", + "jest-runtime": "^27.0.5", + "jest-snapshot": "^27.0.5", + "jest-util": "^27.0.2", + "pretty-format": "^27.0.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + } + }, + "jest-config": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.0.5.tgz", + "integrity": "sha512-zCUIXag7QIXKEVN4kUKbDBDi9Q53dV5o3eNhGqe+5zAbt1vLs4VE3ceWaYrOub0L4Y7E9pGfM84TX/0ARcE+Qw==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.0.5", + "@jest/types": "^27.0.2", + "babel-jest": "^27.0.5", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "jest-circus": "^27.0.5", + "jest-environment-jsdom": "^27.0.5", + "jest-environment-node": "^27.0.5", + "jest-get-type": "^27.0.1", + "jest-jasmine2": "^27.0.5", + "jest-regex-util": "^27.0.1", + "jest-resolve": "^27.0.5", + "jest-runner": "^27.0.5", + "jest-util": "^27.0.2", + "jest-validate": "^27.0.2", + "micromatch": "^4.0.4", + "pretty-format": "^27.0.2" + } + }, + "jest-diff": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.2.tgz", + "integrity": "sha512-BFIdRb0LqfV1hBt8crQmw6gGQHVDhM87SpMIZ45FPYKReZYG5er1+5pIn2zKqvrJp6WNox0ylR8571Iwk2Dmgw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.0.1", + "jest-get-type": "^27.0.1", + "pretty-format": "^27.0.2" + } + }, + "jest-docblock": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.1.tgz", + "integrity": "sha512-TA4+21s3oebURc7VgFV4r7ltdIJ5rtBH1E3Tbovcg7AV+oLfD5DcJ2V2vJ5zFA9sL5CFd/d2D6IpsAeSheEdrA==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.0.2.tgz", + "integrity": "sha512-OLMBZBZ6JkoXgUenDtseFRWA43wVl2BwmZYIWQws7eS7pqsIvePqj/jJmEnfq91ALk3LNphgwNK/PRFBYi7ITQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "chalk": "^4.0.0", + "jest-get-type": "^27.0.1", + "jest-util": "^27.0.2", + "pretty-format": "^27.0.2" + } + }, + "jest-environment-jsdom": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.0.5.tgz", + "integrity": "sha512-ToWhViIoTl5738oRaajTMgYhdQL73UWPoV4GqHGk2DPhs+olv8OLq5KoQW8Yf+HtRao52XLqPWvl46dPI88PdA==", + "dev": true, + "requires": { + "@jest/environment": "^27.0.5", + "@jest/fake-timers": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/node": "*", + "jest-mock": "^27.0.3", + "jest-util": "^27.0.2", + "jsdom": "^16.6.0" + } + }, + "jest-environment-node": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.0.5.tgz", + "integrity": "sha512-47qqScV/WMVz5OKF5TWpAeQ1neZKqM3ySwNveEnLyd+yaE/KT6lSMx/0SOx60+ZUcVxPiESYS+Kt2JS9y4PpkQ==", + "dev": true, + "requires": { + "@jest/environment": "^27.0.5", + "@jest/fake-timers": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/node": "*", + "jest-mock": "^27.0.3", + "jest-util": "^27.0.2" + } + }, + "jest-get-type": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.1.tgz", + "integrity": "sha512-9Tggo9zZbu0sHKebiAijyt1NM77Z0uO4tuWOxUCujAiSeXv30Vb5D4xVF4UR4YWNapcftj+PbByU54lKD7/xMg==", + "dev": true + }, + "jest-haste-map": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.0.5.tgz", + "integrity": "sha512-3LFryGSHxwPFHzKIs6W0BGA2xr6g1MvzSjR3h3D8K8Uqy4vbRm/grpGHzbPtIbOPLC6wFoViRrNEmd116QWSkw==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^27.0.1", + "jest-serializer": "^27.0.1", + "jest-util": "^27.0.2", + "jest-worker": "^27.0.2", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.0.5.tgz", + "integrity": "sha512-m3TojR19sFmTn79QoaGy1nOHBcLvtLso6Zh7u+gYxZWGcza4rRPVqwk1hciA5ZOWWZIJOukAcore8JRX992FaA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^27.0.5", + "@jest/source-map": "^27.0.1", + "@jest/test-result": "^27.0.2", + "@jest/types": "^27.0.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.0.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.0.2", + "jest-matcher-utils": "^27.0.2", + "jest-message-util": "^27.0.2", + "jest-runtime": "^27.0.5", + "jest-snapshot": "^27.0.5", + "jest-util": "^27.0.2", + "pretty-format": "^27.0.2", + "throat": "^6.0.1" + } + }, + "jest-leak-detector": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.0.2.tgz", + "integrity": "sha512-TZA3DmCOfe8YZFIMD1GxFqXUkQnIoOGQyy4hFCA2mlHtnAaf+FeOMxi0fZmfB41ZL+QbFG6BVaZF5IeFIVy53Q==", + "dev": true, + "requires": { + "jest-get-type": "^27.0.1", + "pretty-format": "^27.0.2" + } + }, + "jest-matcher-utils": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.0.2.tgz", + "integrity": "sha512-Qczi5xnTNjkhcIB0Yy75Txt+Ez51xdhOxsukN7awzq2auZQGPHcQrJ623PZj0ECDEMOk2soxWx05EXdXGd1CbA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.0.2", + "jest-get-type": "^27.0.1", + "pretty-format": "^27.0.2" + } + }, + "jest-message-util": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.0.2.tgz", + "integrity": "sha512-rTqWUX42ec2LdMkoUPOzrEd1Tcm+R1KfLOmFK+OVNo4MnLsEaxO5zPDb2BbdSmthdM/IfXxOZU60P/WbWF8BTw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.0.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "pretty-format": "^27.0.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + } + } + }, + "jest-mock": { + "version": "27.0.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.0.3.tgz", + "integrity": "sha512-O5FZn5XDzEp+Xg28mUz4ovVcdwBBPfAhW9+zJLO0Efn2qNbYcDaJvSlRiQ6BCZUCVOJjALicuJQI9mRFjv1o9Q==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true + }, + "jest-regex-util": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.1.tgz", + "integrity": "sha512-6nY6QVcpTgEKQy1L41P4pr3aOddneK17kn3HJw6SdwGiKfgCGTvH02hVXL0GU8GEKtPH83eD2DIDgxHXOxVohQ==", + "dev": true + }, + "jest-resolve": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.0.5.tgz", + "integrity": "sha512-Md65pngRh8cRuWVdWznXBB5eDt391OJpdBaJMxfjfuXCvOhM3qQBtLMCMTykhuUKiBMmy5BhqCW7AVOKmPrW+Q==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "chalk": "^4.0.0", + "escalade": "^3.1.1", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.0.2", + "jest-validate": "^27.0.2", + "resolve": "^1.20.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.5.tgz", + "integrity": "sha512-xUj2dPoEEd59P+nuih4XwNa4nJ/zRd/g4rMvjHrZPEBWeWRq/aJnnM6mug+B+Nx+ILXGtfWHzQvh7TqNV/WbuA==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "jest-regex-util": "^27.0.1", + "jest-snapshot": "^27.0.5" + } + }, + "jest-runner": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.0.5.tgz", + "integrity": "sha512-HNhOtrhfKPArcECgBTcWOc+8OSL8GoFoa7RsHGnfZR1C1dFohxy9eLtpYBS+koybAHlJLZzNCx2Y/Ic3iEtJpQ==", + "dev": true, + "requires": { + "@jest/console": "^27.0.2", + "@jest/environment": "^27.0.5", + "@jest/test-result": "^27.0.2", + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-docblock": "^27.0.1", + "jest-environment-jsdom": "^27.0.5", + "jest-environment-node": "^27.0.5", + "jest-haste-map": "^27.0.5", + "jest-leak-detector": "^27.0.2", + "jest-message-util": "^27.0.2", + "jest-resolve": "^27.0.5", + "jest-runtime": "^27.0.5", + "jest-util": "^27.0.2", + "jest-worker": "^27.0.2", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + } + }, + "jest-runtime": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.0.5.tgz", + "integrity": "sha512-V/w/+VasowPESbmhXn5AsBGPfb35T7jZPGZybYTHxZdP7Gwaa+A0EXE6rx30DshHKA98lVCODbCO8KZpEW3hiQ==", + "dev": true, + "requires": { + "@jest/console": "^27.0.2", + "@jest/environment": "^27.0.5", + "@jest/fake-timers": "^27.0.5", + "@jest/globals": "^27.0.5", + "@jest/source-map": "^27.0.1", + "@jest/test-result": "^27.0.2", + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.0.5", + "jest-message-util": "^27.0.2", + "jest-mock": "^27.0.3", + "jest-regex-util": "^27.0.1", + "jest-resolve": "^27.0.5", + "jest-snapshot": "^27.0.5", + "jest-util": "^27.0.2", + "jest-validate": "^27.0.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^16.0.3" + } + }, + "jest-serializer": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.1.tgz", + "integrity": "sha512-svy//5IH6bfQvAbkAEg1s7xhhgHTtXu0li0I2fdKHDsLP2P2MOiscPQIENQep8oU2g2B3jqLyxKKzotZOz4CwQ==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + } + }, + "jest-snapshot": { + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.0.5.tgz", + "integrity": "sha512-H1yFYdgnL1vXvDqMrnDStH6yHFdMEuzYQYc71SnC/IJnuuhW6J16w8GWG1P+qGd3Ag3sQHjbRr0TcwEo/vGS+g==", + "dev": true, + "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.0.5", + "@jest/types": "^27.0.2", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.0.2", + "graceful-fs": "^4.2.4", + "jest-diff": "^27.0.2", + "jest-get-type": "^27.0.1", + "jest-haste-map": "^27.0.5", + "jest-matcher-utils": "^27.0.2", + "jest-message-util": "^27.0.2", + "jest-resolve": "^27.0.5", + "jest-util": "^27.0.2", + "natural-compare": "^1.4.0", + "pretty-format": "^27.0.2", + "semver": "^7.3.2" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "jest-util": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.2.tgz", + "integrity": "sha512-1d9uH3a00OFGGWSibpNYr+jojZ6AckOMCXV2Z4K3YXDnzpkAaXQyIpY14FOJPiUmil7CD+A6Qs+lnnh6ctRbIA==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.0.2.tgz", + "integrity": "sha512-UgBF6/oVu1ofd1XbaSotXKihi8nZhg0Prm8twQ9uCuAfo59vlxCXMPI/RKmrZEVgi3Nd9dS0I8A0wzWU48pOvg==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.0.1", + "leven": "^3.1.0", + "pretty-format": "^27.0.2" + }, + "dependencies": { + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.0.2.tgz", + "integrity": "sha512-8nuf0PGuTxWj/Ytfw5fyvNn/R80iXY8QhIT0ofyImUvdnoaBdT6kob0GmhXR+wO+ALYVnh8bQxN4Tjfez0JgkA==", + "dev": true, + "requires": { + "@jest/test-result": "^27.0.2", + "@jest/types": "^27.0.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.0.2", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.2.tgz", + "integrity": "sha512-EoBdilOTTyOgmHXtw/cPc+ZrCA0KJMrkXzkrPGNwLmnvvlN1nj7MPrxpT7m+otSv2e1TLaVffzDnE/LB14zJMg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3620,22 +4652,23 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true }, - "jsdoctypeparser": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-9.0.0.tgz", - "integrity": "sha512-jrTA2jJIL6/DAEILBEh2/w9QxCuwmvNXIry39Ay/HVfhE3o2yVV0U44blYkqdHA/OKloJEqvJy0xU+GSdE2SIw==", + "jsdoc-type-pratt-parser": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-1.0.4.tgz", + "integrity": "sha512-jzmW9gokeq9+bHPDR1nCeidMyFUikdZlbOhKzh9+/nJqB75XhpNKec1/UuxW5c4+O+Pi31Gc/dCboyfSm/pSpQ==", "dev": true }, "jsdom": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.1.tgz", - "integrity": "sha512-pF73EOsJgwZekbDHEY5VO/yKXUkab/DuvrQB/ANVizbr6UAHJsDdHXuotZYwkJSGQl1JM+ivXaqY+XBDDL4TiA==", + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.6.0.tgz", + "integrity": "sha512-Ty1vmF4NHJkolaEmdjtxTfSfkdb8Ywarwf63f+F8/mDD1uLSSWDxDuMiZxiPhwunLrn9LOSVItWj4bLYsLN3Dg==", "dev": true, "requires": { "abab": "^2.0.5", - "acorn": "^8.0.5", + "acorn": "^8.2.4", "acorn-globals": "^6.0.0", "cssom": "^0.4.4", "cssstyle": "^2.3.0", @@ -3643,12 +4676,13 @@ "decimal.js": "^10.2.1", "domexception": "^2.0.1", "escodegen": "^2.0.0", + "form-data": "^3.0.0", "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.0", "parse5": "6.0.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.9", "saxes": "^5.0.1", "symbol-tree": "^3.2.4", "tough-cookie": "^4.0.0", @@ -3657,32 +4691,15 @@ "webidl-conversions": "^6.1.0", "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.4.4", + "whatwg-url": "^8.5.0", + "ws": "^7.4.5", "xml-name-validator": "^3.0.0" }, "dependencies": { "acorn": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", - "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", - "dev": true - }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - } - }, - "ws": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", - "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", + "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", "dev": true } } @@ -3707,7 +4724,8 @@ "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true }, "json-schema-traverse": { "version": "0.4.1", @@ -3745,6 +4763,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -3753,9 +4772,9 @@ } }, "just-extend": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", - "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", "dev": true }, "keyv": { @@ -3772,6 +4791,12 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, "known-css-properties": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.21.0.tgz", @@ -3787,6 +4812,12 @@ "readable-stream": "^2.0.5" } }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3830,12 +4861,12 @@ "dev": true }, "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==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { - "p-locate": "^5.0.0" + "p-locate": "^4.1.0" } }, "lodash": { @@ -3846,8 +4877,7 @@ "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" }, "lodash.defaults": { "version": "4.2.0", @@ -3894,14 +4924,12 @@ "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 + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" }, "lodash.union": { "version": "4.6.0", @@ -3916,12 +4944,13 @@ "dev": true }, "log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "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, "requires": { - "chalk": "^4.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" } }, "loglevel": { @@ -3956,9 +4985,9 @@ } }, "luxon": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.26.0.tgz", - "integrity": "sha512-+V5QIQ5f6CDXQpWNICELwjwuHdqeJM1UenlZWx5ujcRMc9venvluCjFb4t5NYLhb6IhkbMVOxzVuOqkgMxee2A==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.27.0.tgz", + "integrity": "sha512-VKsFsPggTA0DvnxtJdiExAucKdAnwbCCNlMM5ENvHlxubqWd0xhZcdb4XgZ7QFNhaRhilXCFxHuoObP5BNA4PA==", "optional": true }, "make-dir": { @@ -3970,16 +4999,25 @@ "semver": "^6.0.0" } }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, "map-obj": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.0.tgz", - "integrity": "sha512-NAq0fCmZYGz9UFEQyndp7sisrow4GroyGeKluyKC/chuITZsPyOyC1UJZPJlVFImhXdROIP5xqouRLThT3BbpQ==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", + "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", "dev": true }, "marky": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.1.tgz", - "integrity": "sha512-md9k+Gxa3qLH6sUKpeC2CNkJK/Ld+bEz5X96nYwloqphQE0CKCVEKco/6jxEZixinqNdz5RFi/KaCyfbMDMAXQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.2.tgz", + "integrity": "sha512-k1dB2HNeaNyORco8ulVEhctyEGkKHb2YWAhDsxeFlW2nROIirsctBYzKwwS3Vza+sKTS1zO4Z+n9/+9WbGLIxQ==", "dev": true }, "matcher": { @@ -3997,6 +5035,16 @@ "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", "dev": true }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, "mdast-util-from-markdown": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", @@ -4055,12 +5103,6 @@ "yargs-parser": "^20.2.3" }, "dependencies": { - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, "type-fest": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", @@ -4102,13 +5144,13 @@ } }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "mime": { @@ -4117,16 +5159,16 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", - "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==" + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" }, "mime-types": { - "version": "2.1.29", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", - "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", "requires": { - "mime-db": "1.46.0" + "mime-db": "1.48.0" } }, "mimic-fn": { @@ -4198,89 +5240,6 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, - "mocha": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.2.tgz", - "integrity": "sha512-UdmISwr/5w+uXLPKspgoV7/RXZwKRTiTjJ2/AC5ZiEztIoOYdfKb19+9jNmEInzx5pBsCyJQzarAxqIGBNYJhg==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.1", - "debug": "4.3.1", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.0.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.20", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.1.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "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 - }, - "js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "mocha-each": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mocha-each/-/mocha-each-2.0.1.tgz", - "integrity": "sha512-0ZgWY5ajbnROXkfyaDb+0RAYzDBH3QVow/1zJiyl7lYMRnj1Nid8RDP2+/2TTajB5n4vr21v35MjB72GjFFj2g==", - "dev": true, - "requires": { - "sprintf-js": "^1.0.3" - } - }, - "mocha-logger": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/mocha-logger/-/mocha-logger-1.0.7.tgz", - "integrity": "sha512-aujkeHhu8tTQ623GIFrcUEX9XQgoewu1fgxqQEGaYVWOwOZX3tF25+RIfcUTQ9eB2zuulTfGsavlryCDaRsP0w==", - "dev": true, - "requires": { - "mocha": "^8.1.3" - } - }, "module-alias": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz", @@ -4323,12 +5282,6 @@ "minimatch": "^3.0.4" } }, - "nanoid": { - "version": "3.1.20", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", - "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", - "dev": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4340,13 +5293,13 @@ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, "nise": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/nise/-/nise-4.1.0.tgz", - "integrity": "sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.0.tgz", + "integrity": "sha512-W5WlHu+wvo3PaKLsJJkgPup2LrsXCcm7AWwyNZkUnn5rwPkuPBi3Iwk5SQtN0mv+K65k7nKKjwNQ30wg3wLAQQ==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0", - "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/fake-timers": "^7.0.4", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", "path-to-regexp": "^1.7.0" @@ -4375,16 +5328,28 @@ "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "node-ical": { - "version": "0.12.9", - "resolved": "https://registry.npmjs.org/node-ical/-/node-ical-0.12.9.tgz", - "integrity": "sha512-5nUEZfZPpBpeZbmYCCmNRLsoP08+SGZy/fKxNBX9k67JMUTMFPLEyZ0CXApPDIExX0izMRndG1PsymhEkkSL2Q==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/node-ical/-/node-ical-0.13.0.tgz", + "integrity": "sha512-hfV7HsY0oTehirXLtkKgAdVomSv6/zjSw66z/RTkKfEp9MwwIz1asyE/g9x4ZKWE2YqGnr81Se5zSRcligPY5Q==", "requires": { "moment-timezone": "^0.5.31", - "request": "^2.88.2", + "node-fetch": "^2.6.1", "rrule": "2.6.8", "uuid": "^8.3.1" } }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -4395,27 +5360,27 @@ } }, "node-releases": { - "version": "1.1.71", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", - "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", "dev": true }, "normalize-package-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.1.tgz", - "integrity": "sha512-D/ttLdxo71msR4FF3VgSwK4blHfE3/vGByz1NCeE7/Dh8reQOKNJJjk5L10mLq9jxa+ZHzT1/HLgxljzbXE7Fw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", + "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", "dev": true, "requires": { - "hosted-git-info": "^4.0.0", - "resolve": "^1.17.0", - "semver": "^7.3.2", + "hosted-git-info": "^4.0.1", + "resolve": "^1.20.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" }, "dependencies": { "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -4442,9 +5407,9 @@ "dev": true }, "normalize-url": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", - "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" }, "npm-conf": { "version": "1.1.3", @@ -4512,12 +5477,6 @@ "yargs": "^15.0.2" }, "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, "cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", @@ -4529,49 +5488,6 @@ "wrap-ansi": "^6.2.0" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -4590,9 +5506,9 @@ } }, "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, "yargs": { @@ -4629,7 +5545,8 @@ "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-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true }, "object-assign": { "version": "4.1.1", @@ -4667,12 +5584,6 @@ "mimic-fn": "^2.1.0" } }, - "opencollective-postinstall": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", - "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", - "dev": true - }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -4691,22 +5602,28 @@ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" }, + "p-each-series": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", + "dev": true + }, "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { - "yocto-queue": "^0.1.0" + "p-try": "^2.0.0" } }, "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==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { - "p-limit": "^3.0.2" + "p-limit": "^2.2.0" } }, "p-map": { @@ -4798,9 +5715,9 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, "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==", + "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-to-regexp": { @@ -4814,12 +5731,6 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true - }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -4828,12 +5739,13 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, "pify": { @@ -4842,28 +5754,28 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "optional": true }, - "pkg-dir": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", "dev": true, "requires": { - "find-up": "^5.0.0" + "node-modules-regexp": "^1.0.0" } }, - "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==", + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "requires": { - "semver-compare": "^1.0.0" + "find-up": "^4.0.0" } }, "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -4999,14 +5911,12 @@ } }, "postcss-selector-parser": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz", - "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", + "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", "dev": true, "requires": { "cssesc": "^3.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1", "util-deprecate": "^1.0.2" } }, @@ -5033,9 +5943,9 @@ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" }, "prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", + "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", "dev": true }, "prettier-linter-helpers": { @@ -5047,10 +5957,30 @@ "fast-diff": "^1.1.2" } }, + "pretty-format": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, "pretty-quick": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.0.tgz", - "integrity": "sha512-DtxIxksaUWCgPFN7E1ZZk4+Aav3CCuRdhrDSFZENb404sYMtuo9Zka823F+Mgeyt8Zt3bUiCjFzzWYE9LYqkmQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.1.tgz", + "integrity": "sha512-ZYLGiMoV2jcaas3vTJrLvKAYsxDoXQBUn8OSTxkl67Fyov9lyXivJTl0+2WVh+y6EovGcw7Lm5ThYpH+Sh3XxQ==", "dev": true, "requires": { "chalk": "^3.0.0", @@ -5071,48 +6001,43 @@ "supports-color": "^7.1.0" } }, - "find-up": { + "execa": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" } }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, "ignore": { "version": "5.1.8", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } } } }, @@ -5141,6 +6066,16 @@ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, + "prompts": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", + "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -5148,11 +6083,11 @@ "optional": true }, "proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "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==", "requires": { - "forwarded": "~0.1.2", + "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, @@ -5165,7 +6100,8 @@ "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true }, "pump": { "version": "3.0.0", @@ -5201,6 +6137,12 @@ "ws": "^7.2.3" }, "dependencies": { + "agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "dev": true + }, "extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -5213,16 +6155,6 @@ "yauzl": "^2.10.0" } }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, "get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -5232,40 +6164,14 @@ "pump": "^3.0.0" } }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "https-proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", "dev": true, "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" + "agent-base": "5", + "debug": "4" } } } @@ -5276,9 +6182,9 @@ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, "queue-microtask": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz", - "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, "quick-lru": { @@ -5287,15 +6193,6 @@ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -5338,6 +6235,12 @@ } } }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -5351,9 +6254,9 @@ }, "dependencies": { "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "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 }, "normalize-package-data": { @@ -5393,43 +6296,6 @@ "type-fest": "^0.8.1" }, "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -5461,15 +6327,6 @@ "minimatch": "^3.0.4" } }, - "readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, "redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -5481,14 +6338,14 @@ } }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" }, "regextras": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.7.1.tgz", - "integrity": "sha512-9YXf6xtW+qzQ+hcMQXx95MOvfqXFgsKDZodX3qZB0x2n5Z94ioetIITsBtvJbiOyxa/6s9AtyweBLCdPmPko/w==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz", + "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==", "dev": true }, "release-zalgo": { @@ -5539,6 +6396,7 @@ "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -5562,38 +6420,41 @@ "uuid": "^3.3.2" }, "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true } } }, - "request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "requires": { - "lodash": "^4.17.19" - } - }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "dev": true, - "requires": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -5622,11 +6483,28 @@ } }, "resolve-alpn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.0.0.tgz", - "integrity": "sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.1.2.tgz", + "integrity": "sha512-8OyfzhAtA32LVUsJSke3auIyINcwdh5l3cvYKdKO0nvsYSKuiLfTM5i78PJswFPT8y6cPW+L1v6/hE95chcpDA==", "dev": true }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -5700,11 +6578,6 @@ "tslib": "^1.10.0" } }, - "rrule-alt": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rrule-alt/-/rrule-alt-2.2.8.tgz", - "integrity": "sha1-oxC23Gy8yKEA5Vgj+T9ia9QbFoA=" - }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -5746,13 +6619,8 @@ "semver-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=" - }, - "semver-regex": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.2.tgz", - "integrity": "sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA==", - "dev": true + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "optional": true }, "send": { "version": "0.17.1", @@ -5805,15 +6673,6 @@ "type-fest": "^0.13.1" } }, - "serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, "serve-static": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", @@ -5856,47 +6715,35 @@ "dev": true }, "simple-git": { - "version": "2.37.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.37.0.tgz", - "integrity": "sha512-ZK6qRnP+Xa2v23UEZDNHUfzswsuNCDHOQpWZRkpqNaXn7V5wVBBx3zRJLji3pROJGzrzA7mXwY7preL5EKuAaQ==", + "version": "2.40.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.40.0.tgz", + "integrity": "sha512-7IO/eQwrN5kvS38TTu9ljhG9tx2nn0BTqZOmqpPpp51TvE44YIvLA6fETqEVA8w/SeEfPaVv6mk7Tsk9Jns+ag==", "requires": { "@kwsites/file-exists": "^1.1.1", "@kwsites/promise-deferred": "^1.1.1", - "debug": "^4.3.2" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - } + "debug": "^4.3.1" } }, "sinon": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-10.0.0.tgz", - "integrity": "sha512-XAn5DxtGVJBlBWYrcYKEhWCz7FLwZGdyvANRyK06419hyEpdT0dMc5A8Vcxg5SCGHc40CsqoKsc1bt1CbJPfNw==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-11.1.1.tgz", + "integrity": "sha512-ZSSmlkSyhUWbkF01Z9tEbxZLF/5tRC9eojCdFh33gtQaP7ITQVaMWQHGuFM7Cuf/KEfihuh1tTl3/ABju3AQMg==", "dev": true, "requires": { - "@sinonjs/commons": "^1.8.1", - "@sinonjs/fake-timers": "^6.0.1", - "@sinonjs/samsam": "^5.3.1", - "diff": "^4.0.2", - "nise": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - } + "@sinonjs/commons": "^1.8.3", + "@sinonjs/fake-timers": "^7.1.0", + "@sinonjs/samsam": "^6.0.2", + "diff": "^5.0.0", + "nise": "^5.1.0", + "supports-color": "^7.2.0" } }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -5914,9 +6761,9 @@ } }, "socket.io": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.0.0.tgz", - "integrity": "sha512-/c1riZMV/4yz7KEpaMhDQbwhJDIoO55whXaRKgyEBQrLU9zUHXo9rzeTMvTOqwL9mbKfHKdrXcMoCeQ/1YtMsg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.1.2.tgz", + "integrity": "sha512-xK0SD1C7hFrh9+bYoYCdVt+ncixkSLKtNLCax5aEy1o3r5PaO5yQhVb97exIe67cE7lAK+EpyMytXWTWmyZY8w==", "requires": { "@types/cookie": "^0.4.0", "@types/cors": "^2.8.8", @@ -5924,15 +6771,15 @@ "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.1", - "engine.io": "~5.0.0", - "socket.io-adapter": "~2.2.0", + "engine.io": "~5.1.0", + "socket.io-adapter": "~2.3.0", "socket.io-parser": "~4.0.3" } }, "socket.io-adapter": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.2.0.tgz", - "integrity": "sha512-rG49L+FwaVEwuAdeBRq49M97YI3ElVabJPzvHT9S6a2CWhDKnjSFasvwAwSYPRhQzfn4NtDIbCaGYgOCOU/rlg==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.1.tgz", + "integrity": "sha512-8cVkRxI8Nt2wadkY6u60Y4rpW3ejA1rxgcK2JuyIhmF+RMNpTy1QRtkHIDUOf3B4HlQwakMsWbKftMv/71VMmw==" }, "socket.io-parser": { "version": "4.0.4", @@ -5950,6 +6797,16 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "spawn-wrap": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", @@ -5991,9 +6848,9 @@ } }, "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", "dev": true }, "specificity": { @@ -6027,12 +6884,14 @@ "sprintf-js": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "optional": true }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -6045,16 +6904,37 @@ "tweetnacl": "~0.14.0" } }, + "stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } }, "string-width": { "version": "4.2.2", @@ -6115,16 +6995,16 @@ "dev": true }, "stylelint": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.12.0.tgz", - "integrity": "sha512-P8O1xDy41B7O7iXaSlW+UuFbE5+ZWQDb61ndGDxKIt36fMH50DtlQTbwLpFLf8DikceTAb3r6nPrRv30wBlzXw==", + "version": "13.13.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.13.1.tgz", + "integrity": "sha512-Mv+BQr5XTUrKqAXmpqm6Ddli6Ief+AiPZkRsIrAoUKFuq/ElkUh9ZMYxXD0iQNZ5ADghZKLOWz1h7hTClB7zgQ==", "dev": true, "requires": { "@stylelint/postcss-css-in-js": "^0.37.2", "@stylelint/postcss-markdown": "^0.36.2", "autoprefixer": "^9.8.6", - "balanced-match": "^1.0.0", - "chalk": "^4.1.0", + "balanced-match": "^2.0.0", + "chalk": "^4.1.1", "cosmiconfig": "^7.0.0", "debug": "^4.3.1", "execall": "^2.0.0", @@ -6133,7 +7013,7 @@ "file-entry-cache": "^6.0.1", "get-stdin": "^8.0.0", "global-modules": "^2.0.0", - "globby": "^11.0.2", + "globby": "^11.0.3", "globjoin": "^0.1.4", "html-tags": "^3.1.0", "ignore": "^5.1.8", @@ -6141,10 +7021,10 @@ "imurmurhash": "^0.1.4", "known-css-properties": "^0.21.0", "lodash": "^4.17.21", - "log-symbols": "^4.0.0", + "log-symbols": "^4.1.0", "mathml-tag-names": "^2.1.3", "meow": "^9.0.0", - "micromatch": "^4.0.2", + "micromatch": "^4.0.4", "normalize-selector": "^0.2.0", "postcss": "^7.0.35", "postcss-html": "^0.36.0", @@ -6154,7 +7034,7 @@ "postcss-safe-parser": "^4.0.2", "postcss-sass": "^0.4.4", "postcss-scss": "^2.1.1", - "postcss-selector-parser": "^6.0.4", + "postcss-selector-parser": "^6.0.5", "postcss-syntax": "^0.36.2", "postcss-value-parser": "^4.1.0", "resolve-from": "^5.0.0", @@ -6165,11 +7045,17 @@ "style-search": "^0.1.0", "sugarss": "^2.0.0", "svg-tags": "^1.0.0", - "table": "^6.0.7", - "v8-compile-cache": "^2.2.0", + "table": "^6.6.0", + "v8-compile-cache": "^2.3.0", "write-file-atomic": "^3.0.3" }, "dependencies": { + "balanced-match": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", + "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", + "dev": true + }, "ignore": { "version": "5.1.8", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", @@ -6191,18 +7077,18 @@ "dev": true }, "stylelint-config-recommended": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-4.0.0.tgz", - "integrity": "sha512-sgna89Ng+25Hr9kmmaIxpGWt2LStVm1xf1807PdcWasiPDaOTkOHRL61sINw0twky7QMzafCGToGDnHT/kTHtQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-5.0.0.tgz", + "integrity": "sha512-c8aubuARSu5A3vEHLBeOSJt1udOdS+1iue7BmJDTSXoCBmfEQmmWX+59vYIj3NQdJBY6a/QRv1ozVFpaB9jaqA==", "dev": true }, "stylelint-config-standard": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-21.0.0.tgz", - "integrity": "sha512-Yf6mx5oYEbQQJxWuW7X3t1gcxqbUx52qC9SMS3saC2ruOVYEyqmr5zSW6k3wXflDjjFrPhar3kp68ugRopmlzg==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-22.0.0.tgz", + "integrity": "sha512-uQVNi87SHjqTm8+4NIP5NMAyY/arXrBgimaaT7skvRfE9u3JKXRK9KBkbr4pVmeciuCcs64kAdjlxfq6Rur7Hw==", "dev": true, "requires": { - "stylelint-config-recommended": "^4.0.0" + "stylelint-config-recommended": "^5.0.0" } }, "stylelint-prettier": { @@ -6239,6 +7125,16 @@ "has-flag": "^4.0.0" } }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, "svg-tags": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", @@ -6252,20 +7148,22 @@ "dev": true }, "table": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", - "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", "requires": { - "ajv": "^7.0.2", - "lodash": "^4.17.20", + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", - "string-width": "^4.2.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" }, "dependencies": { "ajv": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.1.tgz", - "integrity": "sha512-+nu0HDv7kNSOua9apAVc979qd932rrZeb3WOvoiD31A/p1mIE5/9bN2027pE2rOPYEdS3UHzsvof4hY+lM9/WQ==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", + "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -6318,6 +7216,16 @@ } } }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -6334,12 +7242,24 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" }, + "throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -6366,27 +7286,29 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" } }, "tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dev": true, "requires": { "punycode": "^2.1.1" } }, "trim-newlines": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", - "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, "trough": { @@ -6400,6 +7322,15 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -6410,6 +7341,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -6417,7 +7349,8 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true }, "type-check": { "version": "0.4.0", @@ -6464,9 +7397,9 @@ } }, "ua-parser-js": { - "version": "0.7.24", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.24.tgz", - "integrity": "sha512-yo+miGzQx5gakzVK3QFfN0/L9uVhosXBBO7qmnk7c2iw1IhL212wfA3zbnI54B0obGwC/5NWub/iT9sReMx+Fw==", + "version": "0.7.28", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.28.tgz", + "integrity": "sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==", "dev": true }, "unbzip2-stream": { @@ -6491,14 +7424,16 @@ "is-plain-obj": "^2.0.0", "trough": "^1.0.0", "vfile": "^4.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true + } } }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, "unist-util-find-all-after": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz", @@ -6569,6 +7504,25 @@ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" }, + "v8-to-istanbul": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz", + "integrity": "sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, "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", @@ -6588,6 +7542,7 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -6604,6 +7559,14 @@ "is-buffer": "^2.0.0", "unist-util-stringify-position": "^2.0.0", "vfile-message": "^2.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true + } } }, "vfile-message": { @@ -6634,6 +7597,15 @@ "xml-name-validator": "^3.0.0" } }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, "webdriver": { "version": "6.12.1", "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-6.12.1.tgz", @@ -6649,9 +7621,9 @@ }, "dependencies": { "@sindresorhus/is": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.0.tgz", - "integrity": "sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", + "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==", "dev": true }, "@szmarczak/http-timer": { @@ -6664,9 +7636,9 @@ } }, "cacheable-request": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", - "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", "dev": true, "requires": { "clone-response": "^1.0.2", @@ -6674,7 +7646,7 @@ "http-cache-semantics": "^4.0.0", "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", + "normalize-url": "^6.0.1", "responselike": "^2.0.0" } }, @@ -6748,10 +7720,16 @@ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true + }, "p-cancelable": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", - "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", "dev": true }, "responselike": { @@ -6819,9 +7797,9 @@ } }, "serialize-error": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.0.1.tgz", - "integrity": "sha512-r5o60rWFS+8/b49DNAbB+GXZA0SpDpuWE758JxDKgRTga05r3U5lwyksE91dYKDhXSmnu36RALj615E6Aj5pSg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -6874,13 +7852,13 @@ "dev": true }, "whatwg-url": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.6.0.tgz", + "integrity": "sha512-os0KkeeqUOl7ccdDT1qqUcS4KH4tcBTSKK5Nl5WKb2lyxInIZ/CpjkqKa1Ss12mjfdcRX9mHmPPs7/SxG1Hbdw==", "dev": true, "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^2.0.2", + "lodash": "^4.7.0", + "tr46": "^2.1.0", "webidl-conversions": "^6.1.0" } }, @@ -6898,65 +7876,11 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "which-pm-runs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", - "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 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 - }, - "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" - } - } - } - }, "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==" }, - "workerpool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", - "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", - "dev": true - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -6986,9 +7910,9 @@ } }, "ws": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz", - "integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==" + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" }, "xml-name-validator": { "version": "3.0.0", @@ -7003,9 +7927,9 @@ "dev": true }, "y18n": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", - "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yallist": { @@ -7035,23 +7959,11 @@ } }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "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 }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", @@ -7061,12 +7973,6 @@ "fd-slicer": "~1.1.0" } }, - "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 - }, "zip-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", diff --git a/package.json b/package.json index 0f1f1ddf..d1ba105b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "magicmirror", - "version": "2.15.0", + "version": "2.16.0-develop", "description": "The open source modular smart mirror platform.", "main": "js/electron.js", "scripts": { @@ -10,18 +10,20 @@ "install": "echo \"Installing vendor files ...\n\" && cd vendor && npm install --loglevel=error", "install-fonts": "echo \"Installing fonts ...\n\" && cd fonts && npm install --loglevel=error", "postinstall": "npm run install-fonts && echo \"MagicMirror installation finished successfully! \n\"", - "test": "NODE_ENV=test mocha tests --recursive", - "test:coverage": "NODE_ENV=test nyc --reporter=lcov --reporter=text mocha tests --recursive --timeout=3000", - "test:e2e": "NODE_ENV=test mocha tests/e2e --recursive", - "test:unit": "NODE_ENV=test mocha tests/unit --recursive", - "test:prettier": "prettier --check **/*.{js,css,json,md,yml}", + "test": "NODE_ENV=test jest -i --forceExit", + "test:coverage": "NODE_ENV=test nyc --reporter=lcov --reporter=text jest -i --forceExit", + "test:e2e": "NODE_ENV=test jest --selectProjects e2e -i --forceExit", + "test:unit": "NODE_ENV=test jest --selectProjects unit -i --forceExit", + "test:prettier": "prettier . --check", "test:js": "eslint js/**/*.js modules/default/**/*.js clientonly/*.js serveronly/*.js translations/*.js vendor/*.js tests/**/*.js config/* --config .eslintrc.json --quiet", "test:css": "stylelint css/main.css modules/default/**/*.css --config .stylelintrc.json", "test:calendar": "node ./modules/default/calendar/debug.js", "config:check": "node js/check_config.js", - "lint:prettier": "prettier --write **/*.{js,css,json,md,yml}", + "lint:prettier": "prettier . --write", "lint:js": "eslint js/**/*.js modules/default/**/*.js clientonly/*.js serveronly/*.js translations/*.js vendor/*.js tests/**/*.js config/* --config .eslintrc.json --fix", - "lint:css": "stylelint css/main.css modules/default/**/*.css --config .stylelintrc.json --fix" + "lint:css": "stylelint css/main.css modules/default/**/*.css --config .stylelintrc.json --fix", + "lint:staged": "pretty-quick --staged", + "prepare": "[ -f node_modules/.bin/husky ] && husky install || echo no husky installed." }, "repository": { "type": "git", @@ -43,60 +45,74 @@ }, "homepage": "https://magicmirror.builders", "devDependencies": { - "chai": "^4.3.4", - "chai-as-promised": "^7.1.1", - "eslint-config-prettier": "^8.1.0", - "eslint-plugin-jsdoc": "^32.3.0", - "eslint-plugin-prettier": "^3.3.1", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-jsdoc": "^35.4.0", + "eslint-plugin-prettier": "^3.4.0", + "eslint-plugin-jest": "^24.3.6", "express-basic-auth": "^1.2.0", - "husky": "^4.3.8", - "jsdom": "^16.5.1", + "husky": "^6.0.0", + "jest": "27.0.5", + "jsdom": "^16.6.0", "lodash": "^4.17.21", - "mocha": "^8.3.2", - "mocha-each": "^2.0.1", - "mocha-logger": "^1.0.7", "nyc": "^15.1.0", - "prettier": "^2.2.1", - "pretty-quick": "^3.1.0", - "sinon": "^10.0.0", + "prettier": "^2.3.1", + "pretty-quick": "^3.1.1", + "sinon": "^11.1.1", "spectron": "^13.0.0", - "stylelint": "^13.12.0", + "stylelint": "^13.13.1", "stylelint-config-prettier": "^8.0.2", - "stylelint-config-standard": "^21.0.0", + "stylelint-config-standard": "^22.0.0", "stylelint-prettier": "^1.2.0" }, "optionalDependencies": { - "electron": "^11.3.0" + "electron": "^11.4.9" }, "dependencies": { "colors": "^1.4.0", - "console-stamp": "^3.0.0-rc4.2", - "digest-fetch": "^1.1.6", - "eslint": "^7.23.0", + "console-stamp": "^3.0.2", + "digest-fetch": "^1.2.0", + "eslint": "^7.29.0", "express": "^4.17.1", - "express-ipfilter": "^1.1.2", + "express-ipfilter": "^1.2.0", "feedme": "^2.0.2", - "helmet": "^4.4.1", - "iconv-lite": "^0.6.2", + "helmet": "^4.6.0", + "iconv-lite": "^0.6.3", "module-alias": "^2.2.2", "moment": "^2.29.1", "node-fetch": "^2.6.1", - "node-ical": "^0.12.9", - "rrule": "^2.6.8", - "rrule-alt": "^2.2.8", - "simple-git": "^2.37.0", - "socket.io": "^4.0.0" + "node-ical": "^0.13.0", + "simple-git": "^2.40.0", + "socket.io": "^4.1.2" }, "_moduleAliases": { "node_helper": "js/node_helper.js", "logger": "js/logger.js" }, "engines": { - "node": ">=10" + "node": ">=12" }, - "husky": { - "hooks": { - "pre-commit": "pretty-quick --staged" - } + "jest": { + "verbose": true, + "projects": [ + { + "displayName": "unit", + "testMatch": [ + "**/tests/unit/**/*.[jt]s?(x)" + ], + "testPathIgnorePatterns": [ + "/tests/unit/mocks" + ] + }, + { + "displayName": "e2e", + "testMatch": [ + "**/tests/e2e/**/*.[jt]s?(x)" + ], + "testPathIgnorePatterns": [ + "/tests/e2e/modules/mocks", + "/tests/e2e/global-setup.js" + ] + } + ] } } diff --git a/serveronly/index.js b/serveronly/index.js index 136eaa00..00d6b64b 100644 --- a/serveronly/index.js +++ b/serveronly/index.js @@ -1,8 +1,8 @@ const app = require("../js/app.js"); const Log = require("logger"); -app.start(function (config) { - var bindAddress = config.address ? config.address : "localhost"; - var httpType = config.useHttps ? "https" : "http"; +app.start((config) => { + const bindAddress = config.address ? config.address : "localhost"; + const httpType = config.useHttps ? "https" : "http"; Log.log("\nReady to go! Please point your browser to: " + httpType + "://" + bindAddress + ":" + config.port); }); diff --git a/tests/configs/data/calendar_test_recurring.ics b/tests/configs/data/calendar_test_recurring.ics new file mode 100644 index 00000000..635497da --- /dev/null +++ b/tests/configs/data/calendar_test_recurring.ics @@ -0,0 +1,37 @@ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-WR-CALNAME:xxx@gmail.com +X-WR-TIMEZONE:Europe/Zurich +BEGIN:VTIMEZONE +TZID:Etc/UTC +X-LIC-LOCATION:Etc/UTC +BEGIN:STANDARD +TZOFFSETFROM:+0000 +TZOFFSETTO:+0000 +TZNAME:GMT +DTSTART:19700101T00000--äüüßßß-0 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;VALUE=DATE:20210325 +DTEND;VALUE=DATE:20210326 +RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1 +DTSTAMP:20210421T154106Z +UID:zzz@google.com +REATED:20200831T200244Z +DESCRIPTION: +LAST-MODIFIED:20200831T200244Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Birthday +TRANSP:OPAQUE +BEGIN:VALARM +ACTION:DISPLAY +DESCRIPTION:This is an event reminder +TRIGGER:-P0DT7H0M0S +END:VALARM +END:VEVENT diff --git a/tests/configs/data/feed_test_rodrigoramirez.xml b/tests/configs/data/feed_test_rodrigoramirez.xml index dbce18e9..b781a8a8 100644 --- a/tests/configs/data/feed_test_rodrigoramirez.xml +++ b/tests/configs/data/feed_test_rodrigoramirez.xml @@ -1,44 +1,44 @@ - + + + + Rodrigo Ramírez Norambuena + + https://rodrigoramirez.com + Temas sobre Linux, VoIP, Open Source, tecnología y lo relacionado. + Fri, 21 Oct 2016 21:30:22 +0000 + es-ES + hourly + 1 + https://wordpress.org/?v=4.7.3 + + QPanel 0.13.0 + https://rodrigoramirez.com/qpanel-0-13-0/ + https://rodrigoramirez.com/qpanel-0-13-0/#comments + Tue, 20 Sep 2016 11:16:08 +0000 + + + + + + + + + + + - - Rodrigo Ramírez Norambuena - - https://rodrigoramirez.com - Temas sobre Linux, VoIP, Open Source, tecnología y lo relacionado. - Fri, 21 Oct 2016 21:30:22 +0000 - es-ES - hourly - 1 - https://wordpress.org/?v=4.7.3 - - QPanel 0.13.0 - https://rodrigoramirez.com/qpanel-0-13-0/ - https://rodrigoramirez.com/qpanel-0-13-0/#comments - Tue, 20 Sep 2016 11:16:08 +0000 - - - - - - - - - - - - - https://rodrigoramirez.com/?p=1299 - Ya está disponible la versión 0.13.0 de QPanel Para instalar esta nueva versión, la debes descargar de https://github.com/roramirez/qpanel/tree/0.13.0 En al README.md puedes encontrar las instrucciones para hacer que funcione en tu sistema. En esta nueva versión cuenta con los siguientes cambios: Se establece un limite para el reciclado del tiempo de conexión a la base […]

+ https://rodrigoramirez.com/?p=1299 + Ya está disponible la versión 0.13.0 de QPanel Para instalar esta nueva versión, la debes descargar de https://github.com/roramirez/qpanel/tree/0.13.0 En al README.md puedes encontrar las instrucciones para hacer que funcione en tu sistema. En esta nueva versión cuenta con los siguientes cambios: Se establece un limite para el reciclado del tiempo de conexión a la base […]

La entrada QPanel 0.13.0 aparece primero en Rodrigo Ramírez Norambuena.

]]>
- Panel monitor callcenter | Qpanel Monitor ColasYa está disponible la versión 0.13.0 de QPanel

+ Panel monitor callcenter | Qpanel Monitor ColasYa está disponible la versión 0.13.0 de QPanel

Para instalar esta nueva versión, la debes descargar de

  • https://github.com/roramirez/qpanel/tree/0.13.0
  • @@ -57,25 +57,25 @@

     

    La entrada QPanel 0.13.0 aparece primero en Rodrigo Ramírez Norambuena.

    ]]> - https://rodrigoramirez.com/qpanel-0-13-0/feed/ - 3 - - - Problema VirtualBox “starting virtual machine” … - https://rodrigoramirez.com/problema-virtualbox-starting-virtual-machine/ - https://rodrigoramirez.com/problema-virtualbox-starting-virtual-machine/#respond - Sat, 10 Sep 2016 22:50:13 +0000 - - - - - + https://rodrigoramirez.com/qpanel-0-13-0/feed/ + 3 + + + Problema VirtualBox “starting virtual machine” … + https://rodrigoramirez.com/problema-virtualbox-starting-virtual-machine/ + https://rodrigoramirez.com/problema-virtualbox-starting-virtual-machine/#respond + Sat, 10 Sep 2016 22:50:13 +0000 + + + + + - https://rodrigoramirez.com/?p=1284 - Después de una actualización de Debian, de la rama stretch/sid, tuve un problema con VirtualBox.  La versión que se actualizó fue a la virtualbox 5.1.4-dfsg-1+b1. El gran problema era que ninguna maquina virtual quería arrancar, se quedaba en un largo limbo con el mensaje “starting virtual machine”, como el de la imagen de a continuación. […]

    + https://rodrigoramirez.com/?p=1284 + Después de una actualización de Debian, de la rama stretch/sid, tuve un problema con VirtualBox.  La versión que se actualizó fue a la virtualbox 5.1.4-dfsg-1+b1. El gran problema era que ninguna maquina virtual quería arrancar, se quedaba en un largo limbo con el mensaje “starting virtual machine”, como el de la imagen de a continuación. […]

    La entrada Problema VirtualBox “starting virtual machine” … aparece primero en Rodrigo Ramírez Norambuena.

    ]]>
    - Después de una actualización de Debian, de la rama stretch/sid, tuve un problema con VirtualBox.  La versión que se actualizó fue a la virtualbox 5.1.4-dfsg-1+b1. El gran problema era que ninguna maquina virtual quería arrancar, se quedaba en un largo limbo con el mensaje “starting virtual machine”, como el de la imagen de a continuación.

    + Después de una actualización de Debian, de la rama stretch/sid, tuve un problema con VirtualBox.  La versión que se actualizó fue a la virtualbox 5.1.4-dfsg-1+b1. El gran problema era que ninguna maquina virtual quería arrancar, se quedaba en un largo limbo con el mensaje “starting virtual machine”, como el de la imagen de a continuación.

    Starting virtual machine ... VirtualBox

    Ninguna, pero ninguna maquina arrancó, se quedaban en ese mensaje. Fue de esos instantes en que sudas helado … 😉

    Con un poco de investigación fue a parar al archivo ~/.VirtualBox/VBoxSVC.log que indicaba

    @@ -85,7 +85,7 @@

     

    Fui… algo de donde agarrarse. Mirando un poco mas se trataba de problemas con los permisos al vboxdrvu, mirando indicaba que tenía 0600.

     

    -
    $ ls -lh /dev/vboxdrvu 
    +
    $ ls -lh /dev/vboxdrvu
      crw------- 1 root root 10, 56 Sep 10 12:47 /dev/vboxdrvu

     

    El tema es que deben estar en 0666,  le cambias los permisos y eso soluciona el problema 🙂

    @@ -95,24 +95,24 @@ $ ls -lh /dev/vboxdrvu crw-rw-rw- 1 root root 10, 56 Sep 10 12:47 /dev/vboxdrvu

    La entrada Problema VirtualBox “starting virtual machine” … aparece primero en Rodrigo Ramírez Norambuena.

    ]]>
    - https://rodrigoramirez.com/problema-virtualbox-starting-virtual-machine/feed/ - 0 -
    - - Mejorando la consola interactiva de Python - https://rodrigoramirez.com/mejorando-la-consola-interactiva-python/ - https://rodrigoramirez.com/mejorando-la-consola-interactiva-python/#comments - Tue, 06 Sep 2016 04:24:43 +0000 - - - - + https://rodrigoramirez.com/problema-virtualbox-starting-virtual-machine/feed/ + 0 + + + Mejorando la consola interactiva de Python + https://rodrigoramirez.com/mejorando-la-consola-interactiva-python/ + https://rodrigoramirez.com/mejorando-la-consola-interactiva-python/#comments + Tue, 06 Sep 2016 04:24:43 +0000 + + + + - https://rodrigoramirez.com/?p=1247 - Cuando estás desarrollando en Python es muy cool estar utilizando la consola interactiva para ir probando cosas antes de ponerlas dentro del archivo de código fuente. La consola de Python funciona y cumple su cometido. Solo al tipear  python  te permite entrar en modo interactivo e ir probando cosas. El punto es que a veces […]

    + https://rodrigoramirez.com/?p=1247 + Cuando estás desarrollando en Python es muy cool estar utilizando la consola interactiva para ir probando cosas antes de ponerlas dentro del archivo de código fuente. La consola de Python funciona y cumple su cometido. Solo al tipear  python  te permite entrar en modo interactivo e ir probando cosas. El punto es que a veces […]

    La entrada Mejorando la consola interactiva de Python aparece primero en Rodrigo Ramírez Norambuena.

    ]]>
    - Cuando estás desarrollando en Python es muy cool estar utilizando la consola interactiva para ir probando cosas antes de ponerlas dentro del archivo de código fuente.

    + Cuando estás desarrollando en Python es muy cool estar utilizando la consola interactiva para ir probando cosas antes de ponerlas dentro del archivo de código fuente.

    La consola de Python funciona y cumple su cometido. Solo al tipear  python  te permite entrar en modo interactivo e ir probando cosas.

    El punto es que a veces uno necesita ir un poco más allá. Como autocomentado de código o resaltado de sintaxis, para eso tengo dos truco que utilizo generalmente.

    Truco a)

    @@ -139,31 +139,31 @@ $ ls -lh /dev/vboxdrvu

    O lo agregas a un bashrc, zshrc o la shell que ocupes.

    La entrada Mejorando la consola interactiva de Python aparece primero en Rodrigo Ramírez Norambuena.

    ]]>
    - https://rodrigoramirez.com/mejorando-la-consola-interactiva-python/feed/ - 4 -
    - - QPanel 0.12.0 con estadísticas - https://rodrigoramirez.com/qpanel-0-12-0-estadisticas/ - https://rodrigoramirez.com/qpanel-0-12-0-estadisticas/#respond - Mon, 22 Aug 2016 04:19:03 +0000 - - - - - - - - - - - + https://rodrigoramirez.com/mejorando-la-consola-interactiva-python/feed/ + 4 + + + QPanel 0.12.0 con estadísticas + https://rodrigoramirez.com/qpanel-0-12-0-estadisticas/ + https://rodrigoramirez.com/qpanel-0-12-0-estadisticas/#respond + Mon, 22 Aug 2016 04:19:03 +0000 + + + + + + + + + + + - https://rodrigoramirez.com/?p=1268 - Ya está disponible una nueva versión de QPanel, esta es la 0.12.0 Para instalar esta nueva versión, debes visitar la siguiente URL https://github.com/roramirez/qpanel/tree/0.12.0 En esta nueva versión las funcionalidades agregadas son: Permite remover los agentes de las cola Posibilidad de cancelar llamadas que están en espera de atención Estadísticas por rango de fecha obtenidas desde […]

    + https://rodrigoramirez.com/?p=1268 + Ya está disponible una nueva versión de QPanel, esta es la 0.12.0 Para instalar esta nueva versión, debes visitar la siguiente URL https://github.com/roramirez/qpanel/tree/0.12.0 En esta nueva versión las funcionalidades agregadas son: Permite remover los agentes de las cola Posibilidad de cancelar llamadas que están en espera de atención Estadísticas por rango de fecha obtenidas desde […]

    La entrada QPanel 0.12.0 con estadísticas aparece primero en Rodrigo Ramírez Norambuena.

    ]]>
    - Panel monitor callcenter | Qpanel Monitor ColasYa está disponible una nueva versión de QPanel, esta es la 0.12.0

    + Panel monitor callcenter | Qpanel Monitor ColasYa está disponible una nueva versión de QPanel, esta es la 0.12.0

    Para instalar esta nueva versión, debes visitar la siguiente URL

    • https://github.com/roramirez/qpanel/tree/0.12.0
    • @@ -178,31 +178,31 @@ $ ls -lh /dev/vboxdrvu

      Si deseas colaborar con el proyecto puedes agregar nuevas sugerencias mediante un issue ó colaborar mediante mediante un Pull Request

      La entrada QPanel 0.12.0 con estadísticas aparece primero en Rodrigo Ramírez Norambuena.

      ]]> - https://rodrigoramirez.com/qpanel-0-12-0-estadisticas/feed/ - 0 - - - QPanel 0.11.0 con Spy, Whisper y mas - https://rodrigoramirez.com/qpanel-spy-supervisor/ - https://rodrigoramirez.com/qpanel-spy-supervisor/#comments - Thu, 21 Jul 2016 01:53:21 +0000 - - - - - - - - - - - + https://rodrigoramirez.com/qpanel-0-12-0-estadisticas/feed/ + 0 + + + QPanel 0.11.0 con Spy, Whisper y mas + https://rodrigoramirez.com/qpanel-spy-supervisor/ + https://rodrigoramirez.com/qpanel-spy-supervisor/#comments + Thu, 21 Jul 2016 01:53:21 +0000 + + + + + + + + + + + - https://rodrigoramirez.com/?p=1245 - Ya está disponible una nueva versión de QPanel, esta es la 0.11.0 Para instalar esta nueva versión, debes visitar la siguiente URL https://github.com/roramirez/qpanel/tree/0.11.0 Esta versión hemos agregado  algunas funcionalidades que los usuarios  han ido solicitando. Para esta versión es posible realizar Spy, Whisper o Barge a un canal para la supervisión de los miembros que […]

      + https://rodrigoramirez.com/?p=1245 + Ya está disponible una nueva versión de QPanel, esta es la 0.11.0 Para instalar esta nueva versión, debes visitar la siguiente URL https://github.com/roramirez/qpanel/tree/0.11.0 Esta versión hemos agregado  algunas funcionalidades que los usuarios  han ido solicitando. Para esta versión es posible realizar Spy, Whisper o Barge a un canal para la supervisión de los miembros que […]

      La entrada QPanel 0.11.0 con Spy, Whisper y mas aparece primero en Rodrigo Ramírez Norambuena.

      ]]>
      - Panel monitor callcenter | Qpanel Monitor ColasYa está disponible una nueva versión de QPanel, esta es la 0.11.0

      + Panel monitor callcenter | Qpanel Monitor ColasYa está disponible una nueva versión de QPanel, esta es la 0.11.0

      Para instalar esta nueva versión, debes visitar la siguiente URL

      • https://github.com/roramirez/qpanel/tree/0.11.0
      • @@ -216,22 +216,22 @@ $ ls -lh /dev/vboxdrvu

        El proyecto siempre está abierto a nuevas sugerencias las cuales puedes agregar mediante un issue.

        La entrada QPanel 0.11.0 con Spy, Whisper y mas aparece primero en Rodrigo Ramírez Norambuena.

        ]]> - https://rodrigoramirez.com/qpanel-spy-supervisor/feed/ - 4 - - - Añadir Swap a un sistema - https://rodrigoramirez.com/crear-swap/ - https://rodrigoramirez.com/crear-swap/#respond - Fri, 15 Jul 2016 05:07:43 +0000 - - + https://rodrigoramirez.com/qpanel-spy-supervisor/feed/ + 4 + + + Añadir Swap a un sistema + https://rodrigoramirez.com/crear-swap/ + https://rodrigoramirez.com/crear-swap/#respond + Fri, 15 Jul 2016 05:07:43 +0000 + + - https://rodrigoramirez.com/?p=1234 - Algo que me toma generalmente hacer es cuando trabajo con maquina virtuales es asignar una cantidad determinada de Swap. La  memoria swap es un espacio de intercambio en disco para cuando el sistema ya no puede utilizar más memoria RAM. El problema para mi es que algunos sistemas de maquinas virtuales no asignan por defecto […]

        + https://rodrigoramirez.com/?p=1234 + Algo que me toma generalmente hacer es cuando trabajo con maquina virtuales es asignar una cantidad determinada de Swap. La  memoria swap es un espacio de intercambio en disco para cuando el sistema ya no puede utilizar más memoria RAM. El problema para mi es que algunos sistemas de maquinas virtuales no asignan por defecto […]

        La entrada Añadir Swap a un sistema aparece primero en Rodrigo Ramírez Norambuena.

        ]]>
        - Algo que me toma generalmente hacer es cuando trabajo con maquina virtuales es asignar una cantidad determinada de Swap.

        + Algo que me toma generalmente hacer es cuando trabajo con maquina virtuales es asignar una cantidad determinada de Swap.

        La  memoria swap es un espacio de intercambio en disco para cuando el sistema ya no puede utilizar más memoria RAM.

        El problema para mi es que algunos sistemas de maquinas virtuales no asignan por defecto un espacio para la Swap, lo que te lleva a que el sistema pueda tener crash durante la ejecución.

        Para comprobar la asignación de memoria, al ejecutar el comando free nos debería mostrar como algo similar a lo siguiente

        @@ -271,27 +271,27 @@ Swap:         3071          0       3071

         

        La entrada Añadir Swap a un sistema aparece primero en Rodrigo Ramírez Norambuena.

        ]]>
        - https://rodrigoramirez.com/crear-swap/feed/ - 0 -
        - - QPanel 0.10.0 con vista consolidada - https://rodrigoramirez.com/qpanel-0-10-0-vista-consolidada/ - https://rodrigoramirez.com/qpanel-0-10-0-vista-consolidada/#respond - Mon, 20 Jun 2016 19:32:55 +0000 - - - - - - - + https://rodrigoramirez.com/crear-swap/feed/ + 0 + + + QPanel 0.10.0 con vista consolidada + https://rodrigoramirez.com/qpanel-0-10-0-vista-consolidada/ + https://rodrigoramirez.com/qpanel-0-10-0-vista-consolidada/#respond + Mon, 20 Jun 2016 19:32:55 +0000 + + + + + + + - https://rodrigoramirez.com/?p=1227 - Ya con la release numero 28 la nueva versión 0.10.0 de QPanel ya está disponible. Para instalar esta nueva versión, debes visitar la siguiente URL https://github.com/roramirez/qpanel/tree/0.10.0 Esta versión versión nos preocupamos de realizar mejoras, refactorizaciones y agregamos una nueva funcionalidad. La nueva funcionalidad incluida es  que ahora es posible contar con una vista consolidada para […]

        + https://rodrigoramirez.com/?p=1227 + Ya con la release numero 28 la nueva versión 0.10.0 de QPanel ya está disponible. Para instalar esta nueva versión, debes visitar la siguiente URL https://github.com/roramirez/qpanel/tree/0.10.0 Esta versión versión nos preocupamos de realizar mejoras, refactorizaciones y agregamos una nueva funcionalidad. La nueva funcionalidad incluida es  que ahora es posible contar con una vista consolidada para […]

        La entrada QPanel 0.10.0 con vista consolidada aparece primero en Rodrigo Ramírez Norambuena.

        ]]>
        - Panel monitor callcenter | Qpanel Monitor ColasYa con la release numero 28 la nueva versión 0.10.0 de QPanel ya está disponible.

        + Panel monitor callcenter | Qpanel Monitor ColasYa con la release numero 28 la nueva versión 0.10.0 de QPanel ya está disponible.

        Para instalar esta nueva versión, debes visitar la siguiente URL

        • https://github.com/roramirez/qpanel/tree/0.10.0
        • @@ -301,29 +301,29 @@ Swap:         3071          0       3071

          El proyecto siempre está abierto a nuevas sugerencias las cuales puedes agregar mediante un issue.

          La entrada QPanel 0.10.0 con vista consolidada aparece primero en Rodrigo Ramírez Norambuena.

          ]]> - https://rodrigoramirez.com/qpanel-0-10-0-vista-consolidada/feed/ - 0 - - - Nerdearla 2016, WebRTC Glue - https://rodrigoramirez.com/nerdearla-2016/ - https://rodrigoramirez.com/nerdearla-2016/#respond - Wed, 15 Jun 2016 17:55:41 +0000 - - - - - - - - - + https://rodrigoramirez.com/qpanel-0-10-0-vista-consolidada/feed/ + 0 + + + Nerdearla 2016, WebRTC Glue + https://rodrigoramirez.com/nerdearla-2016/ + https://rodrigoramirez.com/nerdearla-2016/#respond + Wed, 15 Jun 2016 17:55:41 +0000 + + + + + + + + + - https://rodrigoramirez.com/?p=1218 - Días atrás estuve participando en el evento llamado Nerdearla en Buenos Aires.  El ambiente era genial si eres de esas personas que desde niño sintio curiosidad por ver como funcionan las cosas, donde desarmabas para volver armar lo juguetes. Habían muchas cosas interesantes tanto en las presentaciones, co-working y workshop que se hubieron. Si te […]

          + https://rodrigoramirez.com/?p=1218 + Días atrás estuve participando en el evento llamado Nerdearla en Buenos Aires.  El ambiente era genial si eres de esas personas que desde niño sintio curiosidad por ver como funcionan las cosas, donde desarmabas para volver armar lo juguetes. Habían muchas cosas interesantes tanto en las presentaciones, co-working y workshop que se hubieron. Si te […]

          La entrada Nerdearla 2016, WebRTC Glue aparece primero en Rodrigo Ramírez Norambuena.

          ]]>
          - Días atrás estuve participando en el evento llamado Nerdearla en Buenos Aires.  El ambiente era genial si eres de esas personas que desde niño sintio curiosidad por ver como funcionan las cosas, donde desarmabas para volver armar lo juguetes.

          + Días atrás estuve participando en el evento llamado Nerdearla en Buenos Aires.  El ambiente era genial si eres de esas personas que desde niño sintio curiosidad por ver como funcionan las cosas, donde desarmabas para volver armar lo juguetes.

          Habían muchas cosas interesantes tanto en las presentaciones, co-working y workshop que se hubieron. Si te lo perdiste te recomiendo que estés pendiente para el proximo año.

           

          Te podias encontrar con una nuestra como estaKaypro II

          @@ -338,30 +338,30 @@ Swap:         3071          0       3071  

          La entrada Nerdearla 2016, WebRTC Glue aparece primero en Rodrigo Ramírez Norambuena.

          ]]>
          - https://rodrigoramirez.com/nerdearla-2016/feed/ - 0 -
          - - QPanel 0.9.0 - https://rodrigoramirez.com/qpanel-0-9-0/ - https://rodrigoramirez.com/qpanel-0-9-0/#respond - Mon, 09 May 2016 18:40:23 +0000 - - - - - - - - - - + https://rodrigoramirez.com/nerdearla-2016/feed/ + 0 + + + QPanel 0.9.0 + https://rodrigoramirez.com/qpanel-0-9-0/ + https://rodrigoramirez.com/qpanel-0-9-0/#respond + Mon, 09 May 2016 18:40:23 +0000 + + + + + + + + + + - https://rodrigoramirez.com/?p=1206 - El Panel monitor callcenter para colas de Asterisk ya cuenta con una nueva versión, la 0.9.0 Para instalar esta nueva versión, debes visitar la siguiente URL https://github.com/roramirez/qpanel/tree/0.9.0 Esta versión versión nos preocupamos de realizar mejoras y refactorizaciones en el codigo para dar un mejor rendimiento, como también de la compatibilidad con la versión 11 de […]

          + https://rodrigoramirez.com/?p=1206 + El Panel monitor callcenter para colas de Asterisk ya cuenta con una nueva versión, la 0.9.0 Para instalar esta nueva versión, debes visitar la siguiente URL https://github.com/roramirez/qpanel/tree/0.9.0 Esta versión versión nos preocupamos de realizar mejoras y refactorizaciones en el codigo para dar un mejor rendimiento, como también de la compatibilidad con la versión 11 de […]

          La entrada QPanel 0.9.0 aparece primero en Rodrigo Ramírez Norambuena.

          ]]>
          - Panel monitor callcenter | Qpanel Monitor ColasEl Panel monitor callcenter para colas de Asterisk ya cuenta con una nueva versión, la 0.9.0

          + Panel monitor callcenter | Qpanel Monitor ColasEl Panel monitor callcenter para colas de Asterisk ya cuenta con una nueva versión, la 0.9.0

          Para instalar esta nueva versión, debes visitar la siguiente URL

          • https://github.com/roramirez/qpanel/tree/0.9.0
          • @@ -376,35 +376,35 @@ Swap:         3071          0       3071

            El proyecto siempre está abierto a nuevas sugerencias las cuales puedes agregar mediante un issue.

            La entrada QPanel 0.9.0 aparece primero en Rodrigo Ramírez Norambuena.

            ]]> - https://rodrigoramirez.com/qpanel-0-9-0/feed/ - 0 - - - Mandar un email desde la shell - https://rodrigoramirez.com/mandar-un-email-desde-la-shell/ - https://rodrigoramirez.com/mandar-un-email-desde-la-shell/#comments - Wed, 13 Apr 2016 13:05:13 +0000 - - - - - - - - - + https://rodrigoramirez.com/qpanel-0-9-0/feed/ + 0 + + + Mandar un email desde la shell + https://rodrigoramirez.com/mandar-un-email-desde-la-shell/ + https://rodrigoramirez.com/mandar-un-email-desde-la-shell/#comments + Wed, 13 Apr 2016 13:05:13 +0000 + + + + + + + + + - https://rodrigoramirez.com/?p=1172 - Dejo esto por acá ya que es algo que siempre me olvido como es. El tema es enviar un email mediante el comando mail en un servidor con Linux. Si usas mail a secas te va pidiendo los datos para crear el correo, principalmente el body del correo. Para automatizar esto a través de un […]

            + https://rodrigoramirez.com/?p=1172 + Dejo esto por acá ya que es algo que siempre me olvido como es. El tema es enviar un email mediante el comando mail en un servidor con Linux. Si usas mail a secas te va pidiendo los datos para crear el correo, principalmente el body del correo. Para automatizar esto a través de un […]

            La entrada Mandar un email desde la shell aparece primero en Rodrigo Ramírez Norambuena.

            ]]>
            - Dejo esto por acá ya que es algo que siempre me olvido como es. El tema es enviar un email mediante el comando mail en un servidor con Linux.

            + Dejo esto por acá ya que es algo que siempre me olvido como es. El tema es enviar un email mediante el comando mail en un servidor con Linux.

            Si usas mail a secas te va pidiendo los datos para crear el correo, principalmente el body del correo. Para automatizar esto a través de un echo le pasas por pipe a mail

            echo "Cuerpo del mensaje" | mail -s Asunto a@rodrigoramirez.com

            La entrada Mandar un email desde la shell aparece primero en Rodrigo Ramírez Norambuena.

            ]]>
            - https://rodrigoramirez.com/mandar-un-email-desde-la-shell/feed/ - 4 -
            - + https://rodrigoramirez.com/mandar-un-email-desde-la-shell/feed/ + 4 + + diff --git a/tests/unit/functions/weatherforecast_data.json b/tests/configs/data/weatherforecast_data.json similarity index 100% rename from tests/unit/functions/weatherforecast_data.json rename to tests/configs/data/weatherforecast_data.json diff --git a/tests/configs/empty_ipWhiteList.js b/tests/configs/empty_ipWhiteList.js index b2369c46..45728c71 100644 --- a/tests/configs/empty_ipWhiteList.js +++ b/tests/configs/empty_ipWhiteList.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: [], diff --git a/tests/configs/env.js b/tests/configs/env.js index d59f01a9..99bd6b4e 100644 --- a/tests/configs/env.js +++ b/tests/configs/env.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/alert/default.js b/tests/configs/modules/alert/default.js new file mode 100644 index 00000000..8ee282d0 --- /dev/null +++ b/tests/configs/modules/alert/default.js @@ -0,0 +1,34 @@ +/* Magic Mirror Test config sample module alert + * + * By rejas + * MIT Licensed. + */ +let config = { + port: 8080, + ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], + + language: "en", + timeFormat: 24, + units: "metric", + electronOptions: { + webPreferences: { + nodeIntegration: true, + enableRemoteModule: true + } + }, + + modules: [ + { + module: "alert", + config: { + display_time: 1000000, + welcome_message: true + } + } + ] +}; + +/*************** DO NOT EDIT THE LINE BELOW ***************/ +if (typeof module !== "undefined") { + module.exports = config; +} diff --git a/tests/configs/modules/calendar/auth-default.js b/tests/configs/modules/calendar/auth-default.js index dd65c53e..053c18ff 100644 --- a/tests/configs/modules/calendar/auth-default.js +++ b/tests/configs/modules/calendar/auth-default.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/calendar/basic-auth.js b/tests/configs/modules/calendar/basic-auth.js index 8937b2a3..c34998b8 100644 --- a/tests/configs/modules/calendar/basic-auth.js +++ b/tests/configs/modules/calendar/basic-auth.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/calendar/changed-port.js b/tests/configs/modules/calendar/changed-port.js index fa0f7ae7..a7e3b34a 100644 --- a/tests/configs/modules/calendar/changed-port.js +++ b/tests/configs/modules/calendar/changed-port.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/calendar/custom.js b/tests/configs/modules/calendar/custom.js index 3d806ce9..6b0e6707 100644 --- a/tests/configs/modules/calendar/custom.js +++ b/tests/configs/modules/calendar/custom.js @@ -1,5 +1,6 @@ /* Magic Mirror Test config custom calendar * + * By Rejas * MIT Licensed. */ let config = { diff --git a/tests/configs/modules/calendar/default.js b/tests/configs/modules/calendar/default.js index 86f81a36..901a6667 100644 --- a/tests/configs/modules/calendar/default.js +++ b/tests/configs/modules/calendar/default.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/calendar/fail-basic-auth.js b/tests/configs/modules/calendar/fail-basic-auth.js index 7ccb8bce..c48d2471 100644 --- a/tests/configs/modules/calendar/fail-basic-auth.js +++ b/tests/configs/modules/calendar/fail-basic-auth.js @@ -5,8 +5,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/calendar/old-basic-auth.js b/tests/configs/modules/calendar/old-basic-auth.js index fa7b70f3..7d0a146b 100644 --- a/tests/configs/modules/calendar/old-basic-auth.js +++ b/tests/configs/modules/calendar/old-basic-auth.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/calendar/recurring.js b/tests/configs/modules/calendar/recurring.js new file mode 100644 index 00000000..371446a3 --- /dev/null +++ b/tests/configs/modules/calendar/recurring.js @@ -0,0 +1,40 @@ +/* Magic Mirror Test config custom calendar + * + * By Rejas + * MIT Licensed. + */ +let config = { + port: 8080, + ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], + + language: "en", + timeFormat: 12, + units: "metric", + electronOptions: { + webPreferences: { + nodeIntegration: true, + enableRemoteModule: true + } + }, + + modules: [ + { + module: "calendar", + position: "bottom_bar", + config: { + calendars: [ + { + maximumEntries: 6, + maximumNumberOfDays: 3650, + url: "http://localhost:8080/tests/configs/data/calendar_test_recurring.ics" + } + ] + } + } + ] +}; + +/*************** DO NOT EDIT THE LINE BELOW ***************/ +if (typeof module !== "undefined") { + module.exports = config; +} diff --git a/tests/configs/modules/clock/clock_12hr.js b/tests/configs/modules/clock/clock_12hr.js index c4ab07fc..bf3cedff 100644 --- a/tests/configs/modules/clock/clock_12hr.js +++ b/tests/configs/modules/clock/clock_12hr.js @@ -3,8 +3,7 @@ * By Sergey Morozov * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/clock/clock_24hr.js b/tests/configs/modules/clock/clock_24hr.js index 57c29010..7813a10d 100644 --- a/tests/configs/modules/clock/clock_24hr.js +++ b/tests/configs/modules/clock/clock_24hr.js @@ -3,8 +3,7 @@ * By Sergey Morozov * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/clock/clock_displaySeconds_false.js b/tests/configs/modules/clock/clock_displaySeconds_false.js index 5031ab82..292a8283 100644 --- a/tests/configs/modules/clock/clock_displaySeconds_false.js +++ b/tests/configs/modules/clock/clock_displaySeconds_false.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/clock/clock_showPeriodUpper.js b/tests/configs/modules/clock/clock_showPeriodUpper.js index 6fe1840f..5dd30222 100644 --- a/tests/configs/modules/clock/clock_showPeriodUpper.js +++ b/tests/configs/modules/clock/clock_showPeriodUpper.js @@ -3,8 +3,7 @@ * By Sergey Morozov * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/clock/clock_showWeek.js b/tests/configs/modules/clock/clock_showWeek.js index 02b4acf4..ca9d4384 100644 --- a/tests/configs/modules/clock/clock_showWeek.js +++ b/tests/configs/modules/clock/clock_showWeek.js @@ -3,8 +3,7 @@ * By Johan Hammar * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/clock/es/clock_12hr.js b/tests/configs/modules/clock/es/clock_12hr.js index b753a550..82f5bfdb 100644 --- a/tests/configs/modules/clock/es/clock_12hr.js +++ b/tests/configs/modules/clock/es/clock_12hr.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/clock/es/clock_24hr.js b/tests/configs/modules/clock/es/clock_24hr.js index feb55770..8db5aae2 100644 --- a/tests/configs/modules/clock/es/clock_24hr.js +++ b/tests/configs/modules/clock/es/clock_24hr.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/clock/es/clock_showPeriodUpper.js b/tests/configs/modules/clock/es/clock_showPeriodUpper.js index 208d9394..1d24a58a 100644 --- a/tests/configs/modules/clock/es/clock_showPeriodUpper.js +++ b/tests/configs/modules/clock/es/clock_showPeriodUpper.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/clock/es/clock_showWeek.js b/tests/configs/modules/clock/es/clock_showWeek.js index 2a6661e9..d86db2d7 100644 --- a/tests/configs/modules/clock/es/clock_showWeek.js +++ b/tests/configs/modules/clock/es/clock_showWeek.js @@ -1,13 +1,10 @@ /* Magic Mirror Test config for default clock module * Language es for showWeek feature * - * By Rodrigo Ramírez Norambuena - * https://rodrigoramirez.com - * + * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/compliments/compliments_anytime.js b/tests/configs/modules/compliments/compliments_anytime.js index 12ee1d3d..21db9ffb 100644 --- a/tests/configs/modules/compliments/compliments_anytime.js +++ b/tests/configs/modules/compliments/compliments_anytime.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/compliments/compliments_date.js b/tests/configs/modules/compliments/compliments_date.js index 0aed1a96..cc2134bb 100644 --- a/tests/configs/modules/compliments/compliments_date.js +++ b/tests/configs/modules/compliments/compliments_date.js @@ -1,10 +1,8 @@ /* Magic Mirror Test config compliments with date type * * By Rejas - * * MIT Licensed. */ - let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/compliments/compliments_only_anytime.js b/tests/configs/modules/compliments/compliments_only_anytime.js index d93b1d37..145157d9 100644 --- a/tests/configs/modules/compliments/compliments_only_anytime.js +++ b/tests/configs/modules/compliments/compliments_only_anytime.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/compliments/compliments_parts_day.js b/tests/configs/modules/compliments/compliments_parts_day.js index d4a4da76..c04b3a32 100644 --- a/tests/configs/modules/compliments/compliments_parts_day.js +++ b/tests/configs/modules/compliments/compliments_parts_day.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/display.js b/tests/configs/modules/display.js index bf2ae261..d22e3cf5 100644 --- a/tests/configs/modules/display.js +++ b/tests/configs/modules/display.js @@ -1,8 +1,9 @@ /* Magic Mirror Test config for display setters module using the helloworld module * + * By Rejas * MIT Licensed. */ -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], @@ -37,6 +38,7 @@ var config = { } ] }; + /*************** DO NOT EDIT THE LINE BELOW ***************/ if (typeof module !== "undefined") { module.exports = config; diff --git a/tests/configs/modules/helloworld/helloworld.js b/tests/configs/modules/helloworld/helloworld.js index b741d5ed..c0e00458 100644 --- a/tests/configs/modules/helloworld/helloworld.js +++ b/tests/configs/modules/helloworld/helloworld.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/helloworld/helloworld_default.js b/tests/configs/modules/helloworld/helloworld_default.js index d04f2884..9d516aef 100644 --- a/tests/configs/modules/helloworld/helloworld_default.js +++ b/tests/configs/modules/helloworld/helloworld_default.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/newsfeed/prohibited_words.js b/tests/configs/modules/newsfeed/prohibited_words.js index e039385e..f9bfa5cf 100644 --- a/tests/configs/modules/newsfeed/prohibited_words.js +++ b/tests/configs/modules/newsfeed/prohibited_words.js @@ -27,7 +27,8 @@ let config = { url: "http://localhost:8080/tests/configs/data/feed_test_rodrigoramirez.xml" } ], - prohibitedWords: ["QPanel"] + prohibitedWords: ["QPanel"], + showDescription: true } } ] diff --git a/tests/configs/modules/positions.js b/tests/configs/modules/positions.js index 24eed5e2..b99316ce 100644 --- a/tests/configs/modules/positions.js +++ b/tests/configs/modules/positions.js @@ -1,12 +1,9 @@ -/* Magic Mirror Test config for position setters module - * - * For this case is using helloworld module +/* Magic Mirror Test config for position setters module using the helloworld module * * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], @@ -23,9 +20,9 @@ var config = { modules: // Using exotic content. This is why don't accept go to JSON configuration file (function () { - var positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"]; - var modules = Array(); - for (var idx in positions) { + let positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"]; + let modules = Array(); + for (let idx in positions) { modules.push({ module: "helloworld", position: positions[idx], @@ -37,6 +34,7 @@ var config = { return modules; })() }; + /*************** DO NOT EDIT THE LINE BELOW ***************/ if (typeof module !== "undefined") { module.exports = config; diff --git a/tests/configs/modules/weather/currentweather_compliments.js b/tests/configs/modules/weather/currentweather_compliments.js index b2aaeeed..0a039b36 100644 --- a/tests/configs/modules/weather/currentweather_compliments.js +++ b/tests/configs/modules/weather/currentweather_compliments.js @@ -1,10 +1,8 @@ /* Magic Mirror Test config current weather compliments * * By rejas https://github.com/rejas - * * MIT Licensed. */ - let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/weather/currentweather_default.js b/tests/configs/modules/weather/currentweather_default.js index 9d53d3b0..440cc725 100644 --- a/tests/configs/modules/weather/currentweather_default.js +++ b/tests/configs/modules/weather/currentweather_default.js @@ -1,10 +1,8 @@ /* Magic Mirror Test config default weather * * By fewieden https://github.com/fewieden - * * MIT Licensed. */ - let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/weather/currentweather_options.js b/tests/configs/modules/weather/currentweather_options.js index 722aa746..3fcd49b9 100644 --- a/tests/configs/modules/weather/currentweather_options.js +++ b/tests/configs/modules/weather/currentweather_options.js @@ -1,10 +1,8 @@ /* Magic Mirror Test config default weather * * By fewieden https://github.com/fewieden - * * MIT Licensed. */ - let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/weather/currentweather_units.js b/tests/configs/modules/weather/currentweather_units.js index 35bf62b0..9eba6660 100644 --- a/tests/configs/modules/weather/currentweather_units.js +++ b/tests/configs/modules/weather/currentweather_units.js @@ -1,10 +1,8 @@ /* Magic Mirror Test config default weather * * By fewieden https://github.com/fewieden - * * MIT Licensed. */ - let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/weather/forecastweather_default.js b/tests/configs/modules/weather/forecastweather_default.js index 60a83f17..dbe2d7e3 100644 --- a/tests/configs/modules/weather/forecastweather_default.js +++ b/tests/configs/modules/weather/forecastweather_default.js @@ -1,10 +1,8 @@ /* Magic Mirror Test config default weather * * By fewieden https://github.com/fewieden - * * MIT Licensed. */ - let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/weather/forecastweather_options.js b/tests/configs/modules/weather/forecastweather_options.js index ccb2de98..32e0c8af 100644 --- a/tests/configs/modules/weather/forecastweather_options.js +++ b/tests/configs/modules/weather/forecastweather_options.js @@ -1,10 +1,8 @@ /* Magic Mirror Test config default weather * * By fewieden https://github.com/fewieden - * * MIT Licensed. */ - let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/modules/weather/forecastweather_units.js b/tests/configs/modules/weather/forecastweather_units.js new file mode 100644 index 00000000..9d1a54ff --- /dev/null +++ b/tests/configs/modules/weather/forecastweather_units.js @@ -0,0 +1,39 @@ +/* Magic Mirror Test config default weather + * + * By rejas + * MIT Licensed. + */ +let config = { + port: 8080, + ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], + + language: "en", + timeFormat: 24, + units: "imperial", + electronOptions: { + webPreferences: { + nodeIntegration: true, + enableRemoteModule: true + } + }, + + modules: [ + { + module: "weather", + position: "bottom_bar", + config: { + type: "forecast", + location: "Munich", + apiKey: "fake key", + weatherEndpoint: "/forecast/daily", + initialLoadDelay: 3000, + decimalSymbol: "_" + } + } + ] +}; + +/*************** DO NOT EDIT THE LINE BELOW ***************/ +if (typeof module !== "undefined") { + module.exports = config; +} diff --git a/tests/configs/noIpWhiteList.js b/tests/configs/noIpWhiteList.js index 3bc2ed31..28369bea 100644 --- a/tests/configs/noIpWhiteList.js +++ b/tests/configs/noIpWhiteList.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["x.x.x.x"], diff --git a/tests/configs/port_8090.js b/tests/configs/port_8090.js index 91ddee50..99386dd2 100644 --- a/tests/configs/port_8090.js +++ b/tests/configs/port_8090.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8090, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], diff --git a/tests/configs/without_modules.js b/tests/configs/without_modules.js index 18e3ce80..8703374c 100644 --- a/tests/configs/without_modules.js +++ b/tests/configs/without_modules.js @@ -3,8 +3,7 @@ * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. */ - -var config = { +let config = { port: 8080, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.10.1"], diff --git a/tests/e2e/dev_console.js b/tests/e2e/dev_console.js index 4e5d1ca1..2a607e5b 100644 --- a/tests/e2e/dev_console.js +++ b/tests/e2e/dev_console.js @@ -1,26 +1,17 @@ const helpers = require("./global-setup"); -const expect = require("chai").expect; - -const describe = global.describe; -const it = global.it; describe("Development console tests", function () { - // FIXME: This tests fail and crash another tests - // Suspect problem with window focus - return false; - - /* eslint-disable */ helpers.setupTimeout(this); - var app = null; + let app = null; - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/env.js"; }); describe("Without 'dev' commandline argument", function () { - before(function () { + beforeAll(function () { return helpers .startApplication({ args: ["js/electron.js"] @@ -30,17 +21,18 @@ describe("Development console tests", function () { }); }); - after(function () { + afterAll(function () { return helpers.stopApplication(app); }); - it("should not open dev console when absent", function () { - return expect(app.browserWindow.isDevToolsOpened()).to.eventually.equal(false); + it("should not open dev console when absent", async function () { + await app.client.waitUntilWindowLoaded(); + return expect(await app.browserWindow.isDevToolsOpened()).toBe(false); }); }); describe("With 'dev' commandline argument", function () { - before(function () { + beforeAll(function () { return helpers .startApplication({ args: ["js/electron.js", "dev"] @@ -50,13 +42,12 @@ describe("Development console tests", function () { }); }); - after(function () { + afterAll(function () { return helpers.stopApplication(app); }); - it("should open dev console when provided", function () { - return expect(app.browserWindow.isDevToolsOpened()).to.eventually.equal(true); + it("should open dev console when provided", async function () { + expect(await app.client.getWindowCount()).toBe(2); }); }); - /* eslint-enable */ }); diff --git a/tests/e2e/env_spec.js b/tests/e2e/env_spec.js index 9c827055..706274a2 100644 --- a/tests/e2e/env_spec.js +++ b/tests/e2e/env_spec.js @@ -1,18 +1,12 @@ const helpers = require("./global-setup"); const fetch = require("node-fetch"); -const expect = require("chai").expect; - -const describe = global.describe; -const it = global.it; -const beforeEach = global.beforeEach; -const afterEach = global.afterEach; describe("Electron app environment", function () { helpers.setupTimeout(this); - var app = null; + let app = null; - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/env.js"; }); @@ -34,27 +28,27 @@ describe("Electron app environment", function () { it("should open a browserwindow", async function () { await app.client.waitUntilWindowLoaded(); app.browserWindow.focus(); - expect(await app.client.getWindowCount()).to.equal(1); - expect(await app.browserWindow.isMinimized()).to.be.false; - expect(await app.browserWindow.isDevToolsOpened()).to.be.false; - expect(await app.browserWindow.isVisible()).to.be.true; - expect(await app.browserWindow.isFocused()).to.be.true; + expect(await app.client.getWindowCount()).toBe(1); + expect(await app.browserWindow.isMinimized()).toBe(false); + expect(await app.browserWindow.isDevToolsOpened()).toBe(false); + expect(await app.browserWindow.isVisible()).toBe(true); + expect(await app.browserWindow.isFocused()).toBe(true); const bounds = await app.browserWindow.getBounds(); - expect(bounds.width).to.be.above(0); - expect(bounds.height).to.be.above(0); - expect(await app.browserWindow.getTitle()).to.equal("MagicMirror²"); + expect(bounds.width).toBeGreaterThan(0); + expect(bounds.height).toBeGreaterThan(0); + expect(await app.browserWindow.getTitle()).toBe("MagicMirror²"); }); it("get request from http://localhost:8080 should return 200", function (done) { fetch("http://localhost:8080").then((res) => { - expect(res.status).to.equal(200); + expect(res.status).toBe(200); done(); }); }); it("get request from http://localhost:8080/nothing should return 404", function (done) { fetch("http://localhost:8080/nothing").then((res) => { - expect(res.status).to.equal(404); + expect(res.status).toBe(404); done(); }); }); diff --git a/tests/e2e/fonts.js b/tests/e2e/fonts.js index c8c2a063..b1459294 100644 --- a/tests/e2e/fonts.js +++ b/tests/e2e/fonts.js @@ -1,19 +1,15 @@ const helpers = require("./global-setup"); const fetch = require("node-fetch"); -const expect = require("chai").expect; -const forEach = require("mocha-each"); - -const describe = global.describe; describe("All font files from roboto.css should be downloadable", function () { helpers.setupTimeout(this); - var app; - var fontFiles = []; + let app; + const fontFiles = []; // Statements below filters out all 'url' lines in the CSS file - var fileContent = require("fs").readFileSync(__dirname + "/../../fonts/roboto.css", "utf8"); - var regex = /\burl\(['"]([^'"]+)['"]\)/g; - var match = regex.exec(fileContent); + const fileContent = require("fs").readFileSync(__dirname + "/../../fonts/roboto.css", "utf8"); + const regex = /\burl\(['"]([^'"]+)['"]\)/g; + let match = regex.exec(fileContent); while (match !== null) { // Push 1st match group onto fontFiles stack fontFiles.push(match[1]); @@ -21,7 +17,7 @@ describe("All font files from roboto.css should be downloadable", function () { match = regex.exec(fileContent); } - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/without_modules.js"; @@ -34,14 +30,14 @@ describe("All font files from roboto.css should be downloadable", function () { }); }); - after(function () { + afterAll(function () { return helpers.stopApplication(app); }); - forEach(fontFiles).it("should return 200 HTTP code for file '%s'", (fontFile, done) => { - var fontUrl = "http://localhost:8080/fonts/" + fontFile; + test.each(fontFiles)("should return 200 HTTP code for file '%s'", (fontFile, done) => { + const fontUrl = "http://localhost:8080/fonts/" + fontFile; fetch(fontUrl).then((res) => { - expect(res.status).to.equal(200); + expect(res.status).toBe(200); done(); }); }); diff --git a/tests/e2e/global-setup.js b/tests/e2e/global-setup.js index ed6217d3..a1e0685b 100644 --- a/tests/e2e/global-setup.js +++ b/tests/e2e/global-setup.js @@ -1,23 +1,13 @@ /* - * Magic Mirror - * - * Global Setup Test Suite + * Magic Mirror Global Setup Test Suite * * By Rodrigo Ramírez Norambuena https://rodrigoramirez.com * MIT Licensed. - * */ - const Application = require("spectron").Application; const assert = require("assert"); -const chai = require("chai"); -const chaiAsPromised = require("chai-as-promised"); const path = require("path"); - -global.before(function () { - chai.should(); - chai.use(chaiAsPromised); -}); +const EventEmitter = require("events"); exports.getElectronPath = function () { let electronPath = path.join(__dirname, "..", "..", "node_modules", ".bin", "electron"); @@ -27,16 +17,19 @@ exports.getElectronPath = function () { return electronPath; }; -// Set timeout - if this is run within Travis, increase timeout +// Set timeout - if this is run as CI Job, increase timeout exports.setupTimeout = function (test) { if (process.env.CI) { - test.timeout(30000); + jest.setTimeout(30000); } else { - test.timeout(10000); + jest.setTimeout(10000); } }; exports.startApplication = function (options) { + const emitter = new EventEmitter(); + emitter.setMaxListeners(100); + options.path = exports.getElectronPath(); if (process.env.CI) { options.startTimeout = 30000; @@ -45,7 +38,6 @@ exports.startApplication = function (options) { const app = new Application(options); return app.start().then(function () { assert.strictEqual(app.isRunning(), true); - chaiAsPromised.transferPromiseness = app.transferPromiseness; return app; }); }; diff --git a/tests/e2e/ipWhistlist_spec.js b/tests/e2e/ipWhitelist_spec.js similarity index 76% rename from tests/e2e/ipWhistlist_spec.js rename to tests/e2e/ipWhitelist_spec.js index 203bc711..3406e0e7 100644 --- a/tests/e2e/ipWhistlist_spec.js +++ b/tests/e2e/ipWhitelist_spec.js @@ -1,16 +1,10 @@ const helpers = require("./global-setup"); const fetch = require("node-fetch"); -const expect = require("chai").expect; - -const describe = global.describe; -const it = global.it; -const beforeEach = global.beforeEach; -const afterEach = global.afterEach; describe("ipWhitelist directive configuration", function () { helpers.setupTimeout(this); - var app = null; + let app = null; beforeEach(function () { return helpers @@ -27,26 +21,28 @@ describe("ipWhitelist directive configuration", function () { }); describe("Set ipWhitelist without access", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/noIpWhiteList.js"; }); + it("should return 403", function (done) { fetch("http://localhost:8080").then((res) => { - expect(res.status).to.equal(403); + expect(res.status).toBe(403); done(); }); }); }); describe("Set ipWhitelist []", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/empty_ipWhiteList.js"; }); + it("should return 200", function (done) { fetch("http://localhost:8080").then((res) => { - expect(res.status).to.equal(200); + expect(res.status).toBe(200); done(); }); }); diff --git a/tests/e2e/modules/alert_spec.js b/tests/e2e/modules/alert_spec.js new file mode 100644 index 00000000..12e724f0 --- /dev/null +++ b/tests/e2e/modules/alert_spec.js @@ -0,0 +1,32 @@ +const helpers = require("../global-setup"); + +describe("Alert module", function () { + helpers.setupTimeout(this); + + let app = null; + + beforeEach(function () { + return helpers + .startApplication({ + args: ["js/electron.js"] + }) + .then(function (startedApp) { + app = startedApp; + }); + }); + + afterEach(function () { + return helpers.stopApplication(app); + }); + + describe("Default configuration", function () { + beforeAll(function () { + // Set config sample for use in test + process.env.MM_CONFIG_FILE = "tests/configs/modules/alert/default.js"; + }); + + it("should show the welcome message", function () { + return app.client.waitUntilTextExists(".ns-box .ns-box-inner .light.bright.small", "Welcome, start was successful!", 10000); + }); + }); +}); diff --git a/tests/e2e/modules/calendar_spec.js b/tests/e2e/modules/calendar_spec.js index 34cc0164..980eca58 100644 --- a/tests/e2e/modules/calendar_spec.js +++ b/tests/e2e/modules/calendar_spec.js @@ -1,11 +1,5 @@ const helpers = require("../global-setup"); const serverBasicAuth = require("../../servers/basic-auth.js"); -const expect = require("chai").expect; - -const describe = global.describe; -const it = global.it; -const beforeEach = global.beforeEach; -const afterEach = global.afterEach; describe("Calendar module", function () { helpers.setupTimeout(this); @@ -27,7 +21,7 @@ describe("Calendar module", function () { }); describe("Default configuration", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/default.js"; }); @@ -35,18 +29,18 @@ describe("Calendar module", function () { it("should show the default maximumEntries of 10", async () => { await app.client.waitUntilTextExists(".calendar", "TestEvent", 10000); const events = await app.client.$$(".calendar .event"); - return expect(events.length).equals(10); + return expect(events.length).toBe(10); }); it("should show the default calendar symbol in each event", async () => { await app.client.waitUntilTextExists(".calendar", "TestEvent", 10000); const icons = await app.client.$$(".calendar .event .fa-calendar"); - return expect(icons.length).not.equals(0); + return expect(icons.length).not.toBe(0); }); }); describe("Custom configuration", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/custom.js"; }); @@ -54,36 +48,49 @@ describe("Calendar module", function () { it("should show the custom maximumEntries of 4", async () => { await app.client.waitUntilTextExists(".calendar", "TestEvent", 10000); const events = await app.client.$$(".calendar .event"); - return expect(events.length).equals(4); + return expect(events.length).toBe(4); }); it("should show the custom calendar symbol in each event", async () => { await app.client.waitUntilTextExists(".calendar", "TestEvent", 10000); const icons = await app.client.$$(".calendar .event .fa-birthday-cake"); - return expect(icons.length).equals(4); + return expect(icons.length).toBe(4); }); it("should show two custom icons for repeating events", async () => { await app.client.waitUntilTextExists(".calendar", "TestEventRepeat", 10000); const icons = await app.client.$$(".calendar .event .fa-undo"); - return expect(icons.length).equals(2); + return expect(icons.length).toBe(2); }); it("should show two custom icons for day events", async () => { await app.client.waitUntilTextExists(".calendar", "TestEventDay", 10000); const icons = await app.client.$$(".calendar .event .fa-calendar-day"); - return expect(icons.length).equals(2); + return expect(icons.length).toBe(2); + }); + }); + + describe("Recurring event", function () { + beforeAll(function () { + // Set config sample for use in test + process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/recurring.js"; + }); + + it("should show the recurring birthday event 6 times", async () => { + await app.client.waitUntilTextExists(".calendar", "Mar 25th", 10000); + const events = await app.client.$$(".calendar .event"); + return expect(events.length).toBe(6); }); }); describe("Changed port", function () { - before(function () { + beforeAll(function () { serverBasicAuth.listen(8010); // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/changed-port.js"; }); - after(function (done) { + afterAll(function (done) { serverBasicAuth.close(done()); }); @@ -93,7 +100,7 @@ describe("Calendar module", function () { }); describe("Basic auth", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/basic-auth.js"; }); @@ -104,7 +111,7 @@ describe("Calendar module", function () { }); describe("Basic auth by default", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/auth-default.js"; }); @@ -115,7 +122,7 @@ describe("Calendar module", function () { }); describe("Basic auth backward compatibility configuration: DEPRECATED", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/old-basic-auth.js"; }); @@ -126,18 +133,18 @@ describe("Calendar module", function () { }); describe("Fail Basic auth", function () { - before(function () { + beforeAll(function () { serverBasicAuth.listen(8020); // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/fail-basic-auth.js"; }); - after(function (done) { + afterAll(function (done) { serverBasicAuth.close(done()); }); - it("should return No upcoming events", function () { - return app.client.waitUntilTextExists(".calendar", "No upcoming events.", 10000); + it("should show Unauthorized error", function () { + return app.client.waitUntilTextExists(".calendar", "Error in the calendar module. Authorization failed", 10000); }); }); }); diff --git a/tests/e2e/modules/clock_es_spec.js b/tests/e2e/modules/clock_es_spec.js index 46d74e8d..f97fba2f 100644 --- a/tests/e2e/modules/clock_es_spec.js +++ b/tests/e2e/modules/clock_es_spec.js @@ -1,14 +1,16 @@ const helpers = require("../global-setup"); -const describe = global.describe; -const it = global.it; -const beforeEach = global.beforeEach; -const afterEach = global.afterEach; - describe("Clock set to spanish language module", function () { helpers.setupTimeout(this); - var app = null; + let app = null; + + testMatch = async function (element, regex) { + await app.client.waitUntilWindowLoaded(); + const elem = await app.client.$(element); + const txt = await elem.getText(element); + return expect(txt).toMatch(regex); + }; beforeEach(function () { return helpers @@ -25,66 +27,60 @@ describe("Clock set to spanish language module", function () { }); describe("with default 24hr clock config", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/es/clock_24hr.js"; }); it("shows date with correct format", async function () { const dateRegex = /^(?:lunes|martes|miércoles|jueves|viernes|sábado|domingo), \d{1,2} de (?:enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre) de \d{4}$/; - const elem = await app.client.$(".clock .date"); - return elem.getText(".clock .date").should.eventually.match(dateRegex); + return testMatch(".clock .date", dateRegex); }); it("shows time in 24hr format", async function () { const timeRegex = /^(?:2[0-3]|[01]\d):[0-5]\d[0-5]\d$/; - const elem = await app.client.$(".clock .time"); - return elem.getText(".clock .time").should.eventually.match(timeRegex); + return testMatch(".clock .time", timeRegex); }); }); describe("with default 12hr clock config", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/es/clock_12hr.js"; }); it("shows date with correct format", async function () { const dateRegex = /^(?:lunes|martes|miércoles|jueves|viernes|sábado|domingo), \d{1,2} de (?:enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre) de \d{4}$/; - const elem = await app.client.$(".clock .date"); - return elem.getText(".clock .date").should.eventually.match(dateRegex); + return testMatch(".clock .date", dateRegex); }); it("shows time in 12hr format", async function () { const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[ap]m$/; - const elem = await app.client.$(".clock .time"); - return elem.getText(".clock .time").should.eventually.match(timeRegex); + return testMatch(".clock .time", timeRegex); }); }); describe("with showPeriodUpper config enabled", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/es/clock_showPeriodUpper.js"; }); it("shows 12hr time with upper case AM/PM", async function () { const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[AP]M$/; - const elem = await app.client.$(".clock .time"); - return elem.getText(".clock .time").should.eventually.match(timeRegex); + return testMatch(".clock .time", timeRegex); }); }); describe("with showWeek config enabled", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/es/clock_showWeek.js"; }); it("shows week with correct format", async function () { const weekRegex = /^Semana [0-9]{1,2}$/; - const elem = await app.client.$(".clock .week"); - elem.getText(".clock .week").should.eventually.match(weekRegex); + return testMatch(".clock .week", weekRegex); }); }); }); diff --git a/tests/e2e/modules/clock_spec.js b/tests/e2e/modules/clock_spec.js index 0f9e3878..c09f44de 100644 --- a/tests/e2e/modules/clock_spec.js +++ b/tests/e2e/modules/clock_spec.js @@ -1,16 +1,17 @@ const helpers = require("../global-setup"); -const expect = require("chai").expect; const moment = require("moment"); -const describe = global.describe; -const it = global.it; -const beforeEach = global.beforeEach; -const afterEach = global.afterEach; - describe("Clock module", function () { helpers.setupTimeout(this); - var app = null; + let app = null; + + testMatch = async function (element, regex) { + await app.client.waitUntilWindowLoaded(); + const elem = await app.client.$(element); + const txt = await elem.getText(element); + return expect(txt).toMatch(regex); + }; beforeEach(function () { return helpers @@ -27,99 +28,94 @@ describe("Clock module", function () { }); describe("with default 24hr clock config", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/clock_24hr.js"; }); it("should show the date in the correct format", async function () { const dateRegex = /^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (?:January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4}$/; - const elem = await app.client.$(".clock .date"); - return elem.getText(".clock .date").should.eventually.match(dateRegex); + return testMatch(".clock .date", dateRegex); }); it("should show the time in 24hr format", async function () { const timeRegex = /^(?:2[0-3]|[01]\d):[0-5]\d[0-5]\d$/; - const elem = await app.client.$(".clock .time"); - return elem.getText(".clock .time").should.eventually.match(timeRegex); + return testMatch(".clock .time", timeRegex); }); }); describe("with default 12hr clock config", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/clock_12hr.js"; }); it("should show the date in the correct format", async function () { const dateRegex = /^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (?:January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4}$/; - const elem = await app.client.$(".clock .date"); - return elem.getText(".clock .date").should.eventually.match(dateRegex); + return testMatch(".clock .date", dateRegex); }); it("should show the time in 12hr format", async function () { const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[ap]m$/; - const elem = await app.client.$(".clock .time"); - return elem.getText(".clock .time").should.eventually.match(timeRegex); + return testMatch(".clock .time", timeRegex); }); }); describe("with showPeriodUpper config enabled", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/clock_showPeriodUpper.js"; }); it("should show 12hr time with upper case AM/PM", async function () { const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[AP]M$/; - const elem = await app.client.$(".clock .time"); - return elem.getText(".clock .time").should.eventually.match(timeRegex); + return testMatch(".clock .time", timeRegex); }); }); describe("with displaySeconds config disabled", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/clock_displaySeconds_false.js"; }); it("should show 12hr time without seconds am/pm", async function () { const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[ap]m$/; - const elem = await app.client.$(".clock .time"); - return elem.getText(".clock .time").should.eventually.match(timeRegex); + return testMatch(".clock .time", timeRegex); }); }); describe("with showWeek config enabled", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/clock_showWeek.js"; }); it("should show the week in the correct format", async function () { const weekRegex = /^Week [0-9]{1,2}$/; - const elem = await app.client.$(".clock .week"); - return elem.getText(".clock .week").should.eventually.match(weekRegex); + return testMatch(".clock .week", weekRegex); }); it("should show the week with the correct number of week of year", async function () { const currentWeekNumber = moment().week(); const weekToShow = "Week " + currentWeekNumber; + await app.client.waitUntilWindowLoaded(); const elem = await app.client.$(".clock .week"); - return elem.getText(".clock .week").should.eventually.equal(weekToShow); + const txt = await elem.getText(".clock .week"); + return expect(txt).toBe(weekToShow); }); }); describe("with analog clock face enabled", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/clock_analog.js"; }); it("should show the analog clock face", async () => { - await app.client.waitUntilWindowLoaded(10000); + await app.client.waitUntilWindowLoaded(); const clock = await app.client.$$(".clockCircle"); - return expect(clock.length).equals(1); + return expect(clock.length).toBe(1); }); }); }); diff --git a/tests/e2e/modules/compliments_spec.js b/tests/e2e/modules/compliments_spec.js index 8a9da41d..81c6e982 100644 --- a/tests/e2e/modules/compliments_spec.js +++ b/tests/e2e/modules/compliments_spec.js @@ -1,15 +1,9 @@ const helpers = require("../global-setup"); -const expect = require("chai").expect; - -const describe = global.describe; -const it = global.it; -const beforeEach = global.beforeEach; -const afterEach = global.afterEach; describe("Compliments module", function () { helpers.setupTimeout(this); - var app = null; + let app = null; beforeEach(function () { return helpers @@ -26,40 +20,40 @@ describe("Compliments module", function () { }); describe("parts of days", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/compliments/compliments_parts_day.js"; }); it("if Morning compliments for that part of day", async function () { - var hour = new Date().getHours(); + const hour = new Date().getHours(); if (hour >= 3 && hour < 12) { // if morning check const elem = await app.client.$(".compliments"); return elem.getText(".compliments").then(function (text) { - expect(text).to.be.oneOf(["Hi", "Good Morning", "Morning test"]); + expect(["Hi", "Good Morning", "Morning test"]).toContain(text); }); } }); it("if Afternoon show Compliments for that part of day", async function () { - var hour = new Date().getHours(); + const hour = new Date().getHours(); if (hour >= 12 && hour < 17) { - // if morning check + // if afternoon check const elem = await app.client.$(".compliments"); return elem.getText(".compliments").then(function (text) { - expect(text).to.be.oneOf(["Hello", "Good Afternoon", "Afternoon test"]); + expect(["Hello", "Good Afternoon", "Afternoon test"]).toContain(text); }); } }); it("if Evening show Compliments for that part of day", async function () { - var hour = new Date().getHours(); + const hour = new Date().getHours(); if (!(hour >= 3 && hour < 12) && !(hour >= 12 && hour < 17)) { // if evening check const elem = await app.client.$(".compliments"); return elem.getText(".compliments").then(function (text) { - expect(text).to.be.oneOf(["Hello There", "Good Evening", "Evening test"]); + expect(["Hello There", "Good Evening", "Evening test"]).toContain(text); }); } }); @@ -67,7 +61,7 @@ describe("Compliments module", function () { describe("Feature anytime in compliments module", function () { describe("Set anytime and empty compliments for morning, evening and afternoon ", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/compliments/compliments_anytime.js"; }); @@ -75,13 +69,13 @@ describe("Compliments module", function () { it("Show anytime because if configure empty parts of day compliments and set anytime compliments", async function () { const elem = await app.client.$(".compliments"); return elem.getText(".compliments").then(function (text) { - expect(text).to.be.oneOf(["Anytime here"]); + expect(["Anytime here"]).toContain(text); }); }); }); describe("Only anytime present in configuration compliments", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/compliments/compliments_only_anytime.js"; }); @@ -89,7 +83,7 @@ describe("Compliments module", function () { it("Show anytime compliments", async function () { const elem = await app.client.$(".compliments"); return elem.getText(".compliments").then(function (text) { - expect(text).to.be.oneOf(["Anytime here"]); + expect(["Anytime here"]).toContain(text); }); }); }); @@ -97,7 +91,7 @@ describe("Compliments module", function () { describe("Feature date in compliments module", function () { describe("Set date and empty compliments for anytime, morning, evening and afternoon", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/compliments/compliments_date.js"; }); @@ -105,7 +99,7 @@ describe("Compliments module", function () { it("Show happy new year compliment on new years day", async function () { const elem = await app.client.$(".compliments"); return elem.getText(".compliments").then(function (text) { - expect(text).to.be.oneOf(["Happy new year!"]); + expect(["Happy new year!"]).toContain(text); }); }); }); diff --git a/tests/e2e/modules/helloworld_spec.js b/tests/e2e/modules/helloworld_spec.js index 21e33985..95ee1a2d 100644 --- a/tests/e2e/modules/helloworld_spec.js +++ b/tests/e2e/modules/helloworld_spec.js @@ -1,14 +1,9 @@ const helpers = require("../global-setup"); -const describe = global.describe; -const it = global.it; -const beforeEach = global.beforeEach; -const afterEach = global.afterEach; - describe("Test helloworld module", function () { helpers.setupTimeout(this); - var app = null; + let app = null; beforeEach(function () { return helpers @@ -25,26 +20,26 @@ describe("Test helloworld module", function () { }); describe("helloworld set config text", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/helloworld/helloworld.js"; }); it("Test message helloworld module", async function () { - const elem = await app.client.$("helloworld"); - return elem.getText(".helloworld").should.eventually.equal("Test HelloWorld Module"); + const elem = await app.client.$(".helloworld"); + return expect(await elem.getText(".helloworld")).toBe("Test HelloWorld Module"); }); }); describe("helloworld default config text", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/helloworld/helloworld_default.js"; }); it("Test message helloworld module", async function () { - const elem = await app.client.$("helloworld"); - return elem.getText(".helloworld").should.eventually.equal("Hello World!"); + const elem = await app.client.$(".helloworld"); + return expect(await elem.getText(".helloworld")).toBe("Hello World!"); }); }); }); diff --git a/tests/e2e/modules/newsfeed_spec.js b/tests/e2e/modules/newsfeed_spec.js index dae3d86b..fe544a0b 100644 --- a/tests/e2e/modules/newsfeed_spec.js +++ b/tests/e2e/modules/newsfeed_spec.js @@ -1,10 +1,5 @@ const helpers = require("../global-setup"); -const describe = global.describe; -const it = global.it; -const beforeEach = global.beforeEach; -const afterEach = global.afterEach; - describe("Newsfeed module", function () { helpers.setupTimeout(this); @@ -25,7 +20,7 @@ describe("Newsfeed module", function () { }); describe("Default configuration", function () { - before(function () { + beforeAll(function () { process.env.MM_CONFIG_FILE = "tests/configs/modules/newsfeed/default.js"; }); @@ -36,25 +31,37 @@ describe("Newsfeed module", function () { it("should show the newsfeed article", function () { return app.client.waitUntilTextExists(".newsfeed .newsfeed-title", "QPanel", 10000); }); + + it("should NOT show the newsfeed description", async () => { + await app.client.waitUntilTextExists(".newsfeed .newsfeed-title", "QPanel", 10000); + const events = await app.client.$$(".newsfeed .newsfeed-desc"); + return expect(events.length).toBe(0); + }); }); describe("Custom configuration", function () { - before(function () { + beforeAll(function () { process.env.MM_CONFIG_FILE = "tests/configs/modules/newsfeed/prohibited_words.js"; }); it("should not show articles with prohibited words", function () { return app.client.waitUntilTextExists(".newsfeed .newsfeed-title", "Problema VirtualBox", 10000); }); + + it("should show the newsfeed description", async () => { + await app.client.waitUntilTextExists(".newsfeed .newsfeed-title", "Problema VirtualBox", 10000); + const events = await app.client.$$(".newsfeed .newsfeed-desc"); + return expect(events.length).toBe(1); + }); }); describe("Invalid configuration", function () { - before(function () { + beforeAll(function () { process.env.MM_CONFIG_FILE = "tests/configs/modules/newsfeed/incorrect_url.js"; }); - it("should show invalid url warning", function () { - return app.client.waitUntilTextExists(".newsfeed .small", "Error in the Newsfeed module. Incorrect url:", 10000); + it("should show malformed url warning", function () { + return app.client.waitUntilTextExists(".newsfeed .small", "Error in the Newsfeed module. Malformed url.", 10000); }); }); }); diff --git a/tests/e2e/modules/weather_spec.js b/tests/e2e/modules/weather_spec.js index cd386f3c..5698dc6a 100644 --- a/tests/e2e/modules/weather_spec.js +++ b/tests/e2e/modules/weather_spec.js @@ -1,4 +1,3 @@ -const expect = require("chai").expect; const fs = require("fs"); const moment = require("moment"); const path = require("path"); @@ -31,7 +30,7 @@ describe("Weather module", function () { async function getText(element, result) { const elem = await getElement(element); return await elem.getText(element).then(function (text) { - expect(text.trim()).to.equal(result); + expect(text.trim()).toBe(result); }); } @@ -42,12 +41,12 @@ describe("Weather module", function () { describe("Current weather", function () { let template; - before(function () { + beforeAll(function () { template = fs.readFileSync(path.join(__dirname, "..", "..", "..", "modules", "default", "weather", "current.njk"), "utf8"); }); describe("Default configuration", function () { - before(function () { + beforeAll(function () { process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/currentweather_default.js"; }); @@ -94,7 +93,7 @@ describe("Weather module", function () { }); describe("Compliments Integration", function () { - before(function () { + beforeAll(function () { process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/currentweather_compliments.js"; }); @@ -107,7 +106,7 @@ describe("Weather module", function () { }); describe("Configuration Options", function () { - before(function () { + beforeAll(function () { process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/currentweather_options.js"; }); @@ -124,7 +123,7 @@ describe("Weather module", function () { const elem = await getElement(".weather .normal.medium sup i.fa-long-arrow-up"); return elem.getHTML(".weather .normal.medium sup i.fa-long-arrow-up").then(function (text) { - expect(text).to.include("transform:rotate(250deg);"); + expect(text).toContain("transform:rotate(250deg);"); }); }); @@ -139,12 +138,12 @@ describe("Weather module", function () { const weather = generateWeather(); await setup({ template, data: weather }); - return getText(".weather .large.light span.bright", "1°C") && getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -6°C"); + return (await getText(".weather .large.light span.bright", "1°C")) && (await getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -6°C")); }); }); describe("Current weather units", function () { - before(function () { + beforeAll(function () { process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/currentweather_units.js"; }); @@ -161,10 +160,10 @@ describe("Weather module", function () { }); await setup({ template, data: weather }); - return getText(".weather .normal.medium span:nth-child(2)", "6 WSW") && getText(".weather .large.light span.bright", "34,7°") && getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°"); + return (await getText(".weather .normal.medium span:nth-child(2)", "6 WSW")) && (await getText(".weather .large.light span.bright", "34,7°")) && getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°"); }); - it("should render decimalSymbol = ','", async function () { + it("should render custom decimalSymbol = ','", async function () { const weather = generateWeather({ main: { temp: (1.49 * 9) / 5 + 32, @@ -177,7 +176,7 @@ describe("Weather module", function () { }); await setup({ template, data: weather }); - return getText(".weather .normal.medium span:nth-child(3)", "93,7") && getText(".weather .large.light span.bright", "34,7°") && getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°"); + return (await getText(".weather .normal.medium span:nth-child(3)", "93,7")) && (await getText(".weather .large.light span.bright", "34,7°")) && getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°"); }); }); }); @@ -185,12 +184,12 @@ describe("Weather module", function () { describe("Weather Forecast", function () { let template; - before(function () { + beforeAll(function () { template = fs.readFileSync(path.join(__dirname, "..", "..", "..", "modules", "default", "weather", "forecast.njk"), "utf8"); }); describe("Default configuration", function () { - before(function () { + beforeAll(function () { process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/forecastweather_default.js"; }); @@ -201,7 +200,7 @@ describe("Weather module", function () { const days = ["Today", "Tomorrow", "Sun", "Mon", "Tue"]; for (const [index, day] of days.entries()) { - getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(1)`, day); + await getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(1)`, day); } }); @@ -212,7 +211,7 @@ describe("Weather module", function () { const icons = ["day-cloudy", "rain", "day-sunny", "day-sunny", "day-sunny"]; for (const [index, icon] of icons.entries()) { - getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(2) span.wi-${icon}`); + await getElement(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(2) span.wi-${icon}`); } }); @@ -223,7 +222,7 @@ describe("Weather module", function () { const temperatures = ["24.4°", "21.0°", "22.9°", "23.4°", "20.6°"]; for (const [index, temp] of temperatures.entries()) { - getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp); + await getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp); } }); @@ -234,7 +233,7 @@ describe("Weather module", function () { const temperatures = ["15.3°", "13.6°", "13.8°", "13.9°", "10.9°"]; for (const [index, temp] of temperatures.entries()) { - getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(4)`, temp); + await getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(4)`, temp); } }); @@ -248,13 +247,13 @@ describe("Weather module", function () { for (const [index, opacity] of opacities.entries()) { const html = await elem.getHTML(`.weather table.small tr:nth-child(${index + 1})`); - expect(html).to.includes(``); + expect(html).toContain(``); } }); }); describe("Configuration Options", function () { - before(function () { + beforeAll(function () { process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/forecastweather_options.js"; }); @@ -271,7 +270,24 @@ describe("Weather module", function () { const rows = await app.client.$$(".weather table.myTableClass tr.colored"); - expect(rows.length).to.be.equal(5); + expect(rows.length).toBe(5); + }); + }); + + describe("Forecast weather units", function () { + beforeAll(function () { + process.env.MM_CONFIG_FILE = "tests/configs/modules/weather/forecastweather_units.js"; + }); + + it("should render custom decimalSymbol = '_'", async function () { + const weather = generateWeatherForecast(); + await setup({ template, data: weather }); + + const temperatures = ["24_4°", "21_0°", "22_9°", "23_4°", "20_6°"]; + + for (const [index, temp] of temperatures.entries()) { + await getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp); + } }); }); }); diff --git a/tests/e2e/modules_display_spec.js b/tests/e2e/modules_display_spec.js index 3dfcf26f..6132c62f 100644 --- a/tests/e2e/modules_display_spec.js +++ b/tests/e2e/modules_display_spec.js @@ -1,12 +1,9 @@ const helpers = require("./global-setup"); -const describe = global.describe; -const it = global.it; - describe("Display of modules", function () { helpers.setupTimeout(this); - var app = null; + let app = null; beforeEach(function () { return helpers @@ -23,19 +20,19 @@ describe("Display of modules", function () { }); describe("Using helloworld", function () { - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/display.js"; }); it("should show the test header", async () => { const elem = await app.client.$("#module_0_helloworld .module-header", 10000); - return elem.getText("#module_0_helloworld .module-header").should.eventually.equal("TEST_HEADER"); + return expect(await elem.getText("#module_0_helloworld .module-header")).toBe("TEST_HEADER"); }); it("should show no header if no header text is specified", async () => { const elem = await app.client.$("#module_1_helloworld .module-header", 10000); - return elem.getText("#module_1_helloworld .module-header").should.eventually.equal(false); + return expect(await elem.getText("#module_1_helloworld .module-header")).toBe(""); }); }); }); diff --git a/tests/e2e/modules_position_spec.js b/tests/e2e/modules_position_spec.js index 8b86d8ad..7ac1cadd 100644 --- a/tests/e2e/modules_position_spec.js +++ b/tests/e2e/modules_position_spec.js @@ -1,19 +1,16 @@ const helpers = require("./global-setup"); -const describe = global.describe; -const it = global.it; - describe("Position of modules", function () { helpers.setupTimeout(this); - var app = null; + let app = null; describe("Using helloworld", function () { - after(function () { + afterAll(function () { return helpers.stopApplication(app); }); - before(function () { + beforeAll(function () { // Set config sample for use in test process.env.MM_CONFIG_FILE = "tests/configs/modules/positions.js"; return helpers @@ -25,16 +22,15 @@ describe("Position of modules", function () { }); }); - var positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"]; + const positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"]; - var position; - var className; - for (var idx in positions) { - position = positions[idx]; - className = position.replace("_", "."); - it("show text in " + position, function () { + for (const position of positions) { + const className = position.replace("_", "."); + it("should show text in " + position, function () { return app.client.$("." + className).then((result) => { - return result.getText("." + className).should.eventually.equal("Text in " + position); + return result.getText("." + className).then((text) => { + return expect(text).toContain("Text in " + position); + }); }); }); } diff --git a/tests/e2e/port_config.js b/tests/e2e/port_config.js index 9f45f486..da489414 100644 --- a/tests/e2e/port_config.js +++ b/tests/e2e/port_config.js @@ -1,16 +1,10 @@ const helpers = require("./global-setup"); const fetch = require("node-fetch"); -const expect = require("chai").expect; - -const describe = global.describe; -const it = global.it; -const beforeEach = global.beforeEach; -const afterEach = global.afterEach; describe("port directive configuration", function () { helpers.setupTimeout(this); - var app = null; + let app = null; beforeEach(function () { return helpers @@ -27,33 +21,33 @@ describe("port directive configuration", function () { }); describe("Set port 8090", function () { - before(function () { + beforeAll(function () { // Set config sample for use in this test process.env.MM_CONFIG_FILE = "tests/configs/port_8090.js"; }); it("should return 200", function (done) { fetch("http://localhost:8090").then((res) => { - expect(res.status).to.equal(200); + expect(res.status).toBe(200); done(); }); }); }); describe("Set port 8100 on environment variable MM_PORT", function () { - before(function () { + beforeAll(function () { process.env.MM_PORT = 8100; // Set config sample for use in this test process.env.MM_CONFIG_FILE = "tests/configs/port_8090.js"; }); - after(function () { + afterAll(function () { delete process.env.MM_PORT; }); it("should return 200", function (done) { fetch("http://localhost:8100").then((res) => { - expect(res.status).to.equal(200); + expect(res.status).toBe(200); done(); }); }); diff --git a/tests/e2e/translations_spec.js b/tests/e2e/translations_spec.js index 5f0d6053..d05837cd 100644 --- a/tests/e2e/translations_spec.js +++ b/tests/e2e/translations_spec.js @@ -1,8 +1,5 @@ const fs = require("fs"); const path = require("path"); -const chai = require("chai"); -const expect = chai.expect; -const mlog = require("mocha-logger"); const translations = require("../../translations/translations.js"); const helmet = require("helmet"); const { JSDOM } = require("jsdom"); @@ -12,7 +9,7 @@ const sinon = require("sinon"); describe("Translations", function () { let server; - before(function () { + beforeAll(function () { const app = express(); app.use(helmet()); app.use(function (req, res, next) { @@ -24,14 +21,14 @@ describe("Translations", function () { server = app.listen(3000); }); - after(function () { + afterAll(function () { server.close(); }); it("should have a translation file in the specified path", function () { for (let language in translations) { const file = fs.statSync(translations[language]); - expect(file.isFile()).to.be.equal(true); + expect(file.isFile()).toBe(true); } }); @@ -59,9 +56,9 @@ describe("Translations", function () { const loaded = sinon.stub(); MMM.loadTranslations(loaded); - expect(loaded.callCount).to.equal(1); - expect(Translator.load.args.length).to.equal(1); - expect(Translator.load.calledWith(MMM, "translations/en.json", false, sinon.match.func)).to.be.true; + expect(loaded.callCount).toBe(1); + expect(Translator.load.args.length).toBe(1); + expect(Translator.load.calledWith(MMM, "translations/en.json", false, sinon.match.func)).toBe(true); done(); }; @@ -78,10 +75,10 @@ describe("Translations", function () { const loaded = sinon.stub(); MMM.loadTranslations(loaded); - expect(loaded.callCount).to.equal(1); - expect(Translator.load.args.length).to.equal(2); - expect(Translator.load.calledWith(MMM, "translations/de.json", false, sinon.match.func)).to.be.true; - expect(Translator.load.calledWith(MMM, "translations/en.json", true, sinon.match.func)).to.be.true; + expect(loaded.callCount).toBe(1); + expect(Translator.load.args.length).toBe(2); + expect(Translator.load.calledWith(MMM, "translations/de.json", false, sinon.match.func)).toBe(true); + expect(Translator.load.calledWith(MMM, "translations/en.json", true, sinon.match.func)).toBe(true); done(); }; @@ -99,9 +96,9 @@ describe("Translations", function () { const loaded = sinon.stub(); MMM.loadTranslations(loaded); - expect(loaded.callCount).to.equal(1); - expect(Translator.load.args.length).to.equal(1); - expect(Translator.load.calledWith(MMM, "translations/en.json", true, sinon.match.func)).to.be.true; + expect(loaded.callCount).toBe(1); + expect(Translator.load.args.length).toBe(1); + expect(Translator.load.calledWith(MMM, "translations/en.json", true, sinon.match.func)).toBe(true); done(); }; @@ -118,8 +115,8 @@ describe("Translations", function () { const loaded = sinon.stub(); MMM.loadTranslations(loaded); - expect(loaded.callCount).to.equal(1); - expect(Translator.load.callCount).to.equal(0); + expect(loaded.callCount).toBe(1); + expect(Translator.load.callCount).toBe(0); done(); }; @@ -145,8 +142,8 @@ describe("Translations", function () { const { Translator } = dom.window; Translator.load(mmm, translations[language], false, function () { - expect(Translator.translations[mmm.name]).to.be.an("object"); - expect(Object.keys(Translator.translations[mmm.name]).length).to.be.at.least(1); + expect(typeof Translator.translations[mmm.name]).toBe("object"); + expect(Object.keys(Translator.translations[mmm.name]).length).toBeGreaterThanOrEqual(1); done(); }); }; @@ -156,8 +153,9 @@ describe("Translations", function () { describe("Same keys", function () { let base; + let missing = []; - before(function (done) { + beforeAll(function (done) { const dom = new JSDOM( `\ \ \ \