diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fc9f4d1c1..3d7d2e1c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,6 @@ jobs: fail-fast: true matrix: app: - - met-airquality - met-anomalycor - met-cyclone - met-ensemble @@ -50,7 +49,6 @@ jobs: fail-fast: true matrix: app: - - met-airquality - met-anomalycor - met-cyclone - met-ensemble diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 14358727d..483fe9cb7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -16,7 +16,6 @@ jobs: fail-fast: true matrix: deploy: # List of apps to deploy - - met-airquality - met-anomalycor - met-cyclone - met-ensemble diff --git a/.github/workflows/prune-pr-images.yml b/.github/workflows/prune-pr-images.yml index c4f0cd9cf..3bce98dd8 100644 --- a/.github/workflows/prune-pr-images.yml +++ b/.github/workflows/prune-pr-images.yml @@ -12,7 +12,6 @@ jobs: fail-fast: false matrix: app: - - met-airquality - met-anomalycor - met-cyclone - met-ensemble diff --git a/.github/workflows/prune-untagged-images.yml b/.github/workflows/prune-untagged-images.yml index 3e94e2957..94835c7e6 100644 --- a/.github/workflows/prune-untagged-images.yml +++ b/.github/workflows/prune-untagged-images.yml @@ -13,7 +13,6 @@ jobs: fail-fast: false matrix: app: - - met-airquality - met-anomalycor - met-cyclone - met-ensemble diff --git a/MATScommon b/MATScommon index aab90dd56..d10f72ccc 160000 --- a/MATScommon +++ b/MATScommon @@ -1 +1 @@ -Subproject commit aab90dd563a99cf208bb809637040a50d27b6bbb +Subproject commit d10f72ccc7fc94b7fa830f777232aaaeca53f9e9 diff --git a/apps/met-airquality/.eslintrc.json b/apps/met-airquality/.eslintrc.json deleted file mode 100644 index a33ac158f..000000000 --- a/apps/met-airquality/.eslintrc.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "env": { - "node": true, - "browser": true - }, - "parser": "@babel/eslint-parser", - "parserOptions": { - "sourceType": "module", - "requireConfigFile": false, - "allowImportExportEverywhere": true - }, - "extends": ["airbnb", "prettier", "plugin:meteor/recommended"], - "plugins": ["prettier", "meteor"], - "settings": { - "import/resolver": "meteor" - }, - "rules": { - "prettier/prettier": "error", - "react/jsx-filename-extension": "off", - "import/no-absolute-path": "off", - "import/extensions": "off", - // disabled so that we're not expecting to find 'meteor' within - // our dependencies. - // XXX: this *should* be taken care of by eslint-import-resolver-meteor, investigate. - // "import/no-extraneous-dependencies": "off", - "no-underscore-dangle": ["error", { "allow": ["_id", "_ensureIndex"] }], - "object-shorthand": ["error", "always", { "avoidQuotes": false }], - "space-before-function-paren": "off", - // for Meteor API's that rely on `this` context, e.g. Template.onCreated and publications - "func-names": "off", - "prefer-arrow-callback": "off", - - // Vx Team modifications - Warn on rules that would require refactoring to implement. - // We want to be able to turn these back into "error"'s at some point. However, for - // our first pass, we'll only consider the checks that ESLint can auto-fix as errors. - // https://eslint.org/docs/latest/use/configure/rules#rule-severities - "no-undef": "warn", - "no-unused-vars": "warn" - } -} diff --git a/apps/met-airquality/.meteor/.finished-upgraders b/apps/met-airquality/.meteor/.finished-upgraders deleted file mode 100644 index c07b6ff75..000000000 --- a/apps/met-airquality/.meteor/.finished-upgraders +++ /dev/null @@ -1,19 +0,0 @@ -# This file contains information which helps Meteor properly upgrade your -# app when you run 'meteor update'. You should check it into version control -# with your project. - -notices-for-0.9.0 -notices-for-0.9.1 -0.9.4-platform-file -notices-for-facebook-graph-api-2 -1.2.0-standard-minifiers-package -1.2.0-meteor-platform-split -1.2.0-cordova-changes -1.2.0-breaking-changes -1.3.0-split-minifiers-package -1.4.0-remove-old-dev-bundle-link -1.4.1-add-shell-server-package -1.4.3-split-account-service-packages -1.5-add-dynamic-import-package -1.7-split-underscore-from-meteor-base -1.8.3-split-jquery-from-blaze diff --git a/apps/met-airquality/.meteor/.gitignore b/apps/met-airquality/.meteor/.gitignore deleted file mode 100644 index 408303742..000000000 --- a/apps/met-airquality/.meteor/.gitignore +++ /dev/null @@ -1 +0,0 @@ -local diff --git a/apps/met-airquality/.meteor/.id b/apps/met-airquality/.meteor/.id deleted file mode 100644 index 9f44e5f7b..000000000 --- a/apps/met-airquality/.meteor/.id +++ /dev/null @@ -1,7 +0,0 @@ -# This file contains a token that is unique to your project. -# Check it into your repository along with the rest of this directory. -# It can be used for purposes such as: -# - ensuring you don't accidentally deploy one app on top of another -# - providing package authors with aggregated statistics - -1yftguri8ke01hewq6l diff --git a/apps/met-airquality/.meteor/packages b/apps/met-airquality/.meteor/packages deleted file mode 100644 index 74e6222ea..000000000 --- a/apps/met-airquality/.meteor/packages +++ /dev/null @@ -1,31 +0,0 @@ -# Meteor packages used by this project, one per line. -# Check this file (and the other files in this directory) into your repository. -# -# 'meteor add' and 'meteor remove' will edit this file for you, -# but you can also edit it by hand. - -meteor-base@1.5.1 # Packages every Meteor app needs to have -mobile-experience@1.1.1 # Packages for a great mobile UX -mongo@1.16.8 # The database Meteor supports right now -blaze-html-templates # Compile .html files into Meteor Blaze views -reactive-var@1.0.12 # Reactive variable for tracker -jquery@1.11.10 # Helpful client-side library -tracker@1.3.3 # Meteor's client-side reactive programming library -standard-minifier-js@2.8.1 # JS minifier run for production mode -es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers. -ecmascript@0.16.8 # Enable ECMAScript2015+ syntax in app code -shell-server@0.5.0 # Server-side component of the `meteor shell` command -pcel:mysql -seba:minifiers-autoprefixer -session@1.2.1 -momentjs:moment -randyp:mats-common@5.2.3 -accounts-google@1.4.0 -accounts-base@2.2.10 -accounts-ui@1.4.2 -google-config-ui@1.0.3 -dynamic-import@0.7.3 -underscore@1.6.0 -kadira:blaze-layout -ostrio:flow-router-extra -meteorhacks:picker diff --git a/apps/met-airquality/.meteor/platforms b/apps/met-airquality/.meteor/platforms deleted file mode 100644 index efeba1b50..000000000 --- a/apps/met-airquality/.meteor/platforms +++ /dev/null @@ -1,2 +0,0 @@ -server -browser diff --git a/apps/met-airquality/.meteor/release b/apps/met-airquality/.meteor/release deleted file mode 100644 index 966586ce5..000000000 --- a/apps/met-airquality/.meteor/release +++ /dev/null @@ -1 +0,0 @@ -METEOR@2.15 diff --git a/apps/met-airquality/.meteor/versions b/apps/met-airquality/.meteor/versions deleted file mode 100644 index 225c0ca46..000000000 --- a/apps/met-airquality/.meteor/versions +++ /dev/null @@ -1,109 +0,0 @@ -accounts-base@2.2.10 -accounts-google@1.4.0 -accounts-oauth@1.4.3 -accounts-password@2.4.0 -accounts-ui@1.4.2 -accounts-ui-unstyled@1.7.0 -allow-deny@1.1.1 -autoupdate@1.8.0 -babel-compiler@7.10.5 -babel-runtime@1.5.1 -base64@1.0.12 -binary-heap@1.0.11 -blaze@2.8.0 -blaze-html-templates@2.0.1 -blaze-tools@1.1.4 -boilerplate-generator@1.7.2 -caching-compiler@1.2.2 -caching-html-compiler@1.2.2 -callback-hook@1.5.1 -check@1.3.2 -ddp@1.4.1 -ddp-client@2.6.1 -ddp-common@1.4.0 -ddp-rate-limiter@1.2.1 -ddp-server@2.7.0 -diff-sequence@1.1.2 -differential:event-hooks@1.5.0 -dynamic-import@0.7.3 -ecmascript@0.16.8 -ecmascript-runtime@0.8.1 -ecmascript-runtime-client@0.12.1 -ecmascript-runtime-server@0.11.0 -ejson@1.1.3 -email@2.2.5 -es5-shim@4.8.0 -fetch@0.1.4 -geojson-utils@1.0.11 -google-config-ui@1.0.3 -google-oauth@1.4.4 -hot-code-push@1.0.4 -html-tools@1.1.4 -htmljs@1.2.0 -id-map@1.1.1 -inter-process-messaging@0.1.1 -jquery@1.11.11 -kadira:blaze-layout@2.3.0 -launch-screen@2.0.0 -less@4.0.0 -localstorage@1.2.0 -logging@1.3.3 -mdg:validated-method@1.3.0 -meteor@1.11.5 -meteor-base@1.5.1 -meteorhacks:picker@1.0.3 -meteortoys:toykit@10.0.0 -minifier-css@1.6.4 -minifier-js@2.7.5 -minimongo@1.9.3 -mobile-experience@1.1.1 -mobile-status-bar@1.1.0 -modern-browsers@0.1.10 -modules@0.20.0 -modules-runtime@0.13.1 -momentjs:moment@2.30.1 -mongo@1.16.8 -mongo-decimal@0.1.3 -mongo-dev-server@1.1.0 -mongo-id@1.0.8 -msavin:mongol@10.0.1 -natestrauser:select2@4.0.3 -npm-mongo@4.17.2 -oauth@2.2.1 -oauth2@1.3.2 -observe-sequence@1.0.22 -ordered-dict@1.1.0 -ostrio:flow-router-extra@3.10.0 -pcel:mysql@0.1.0 -promise@0.12.2 -random@1.2.1 -randyp:mats-common@5.2.3 -rate-limit@1.1.1 -react-fast-refresh@0.2.8 -reactive-dict@1.3.1 -reactive-var@1.0.12 -reload@1.3.1 -retry@1.1.0 -risul:bootstrap-colorpicker@2.3.6 -routepolicy@1.1.1 -seba:minifiers-autoprefixer@2.0.1 -service-configuration@1.3.3 -session@1.2.1 -sha@1.0.9 -shell-server@0.5.0 -socket-stream-client@0.5.2 -spacebars@1.5.0 -spacebars-compiler@1.3.2 -standard-minifier-js@2.8.1 -templating@1.4.3 -templating-compiler@1.4.2 -templating-runtime@1.6.4 -templating-tools@1.2.3 -tracker@1.3.3 -twbs:bootstrap@3.3.6 -typescript@4.9.5 -underscore@1.6.1 -url@1.3.2 -webapp@1.13.8 -webapp-hashing@1.1.1 -yasinuslu:json-view@1.2.3 diff --git a/apps/met-airquality/.prettierrc b/apps/met-airquality/.prettierrc deleted file mode 100644 index b90ca94e6..000000000 --- a/apps/met-airquality/.prettierrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "printWidth": 88 -} diff --git a/apps/met-airquality/app.css b/apps/met-airquality/app.css deleted file mode 100644 index 5e50cb8e2..000000000 --- a/apps/met-airquality/app.css +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. - */ - -/* CSS declarations go here */ -html, -body { - height: 100%; -} - -@font-face { - font-family: "PublicSans-Regular"; - src: url("/packages/randyp_mats-common/public/fonts/PublicSans-Regular.ttf"); -} - -@font-face { - font-family: "PublicSans-SemiBold"; - src: url("/packages/randyp_mats-common/public/fonts/PublicSans-SemiBold.ttf"); -} - -@font-face { - font-family: "PublicSans-Medium"; - src: url("/packages/randyp_mats-common/public/fonts/PublicSans-Medium.ttf"); -} - -body { - margin-top: 1%; - margin-left: 2%; - margin-right: 2%; - margin-bottom: 1%; - padding: 0; - background: url("/packages/randyp_mats-common/public/img/bg.png") repeat; - font-family: PublicSans-Regular, Arial, Helvetica, sans-serif; - font-size: 15px; - color: #333333; /*#545454;*/ -} - -.main { - width: 100%; - margin: 0; - padding: 0; - background-color: white; - font-family: PublicSans-Regular, Arial, Helvetica, sans-serif; - font-size: 15px; -} - -.modal-backdrop { - background-color: grey; -} - -.modal-header { - background-image: url("/packages/randyp_mats-common/public/img/subtle_grunge_@2X.png"); -} - -.modal-body { - background-image: url("/packages/randyp_mats-common/public/img/texturetastic_gray.png"); -} - -.modal-content { - background-image: url("/packages/randyp_mats-common/public/img/subtle_grunge_@2X.png"); -} - -.modal-footer { - background-image: url("/packages/randyp_mats-common/public/img/subtle_grunge_@2X.png"); -} - -#Mongol.Mongol_expand { - max-width: 720px !important; -} - -#placeholder .button { - position: absolute; - cursor: pointer; -} - -#placeholder div.button { - font-size: smaller; - color: #999; - background-color: #eee; - padding: 2px; -} - -.message { - padding-left: 50px; - font-size: smaller; -} - -hr { - height: 0; - border-top: 1px; - color: #eee; - background-color: #eee; -} - -.spacer { - padding-left: 1em; -} - -.rule { - width: 100%; - height: 7px; - overflow: hidden; -} - -.spacebutton { - background: transparent; - border: none; -} - -.input { - max-width: 100%; -} - -.select2-selection--multiple { - max-height: 200px; - overflow: auto; -} - -.boldedPublicSans { - font-family: PublicSans-SemiBold, Arial, Helvetica, serif; -} - -.regularPublicSans { - font-family: PublicSans-Regular, Arial, Helvetica, sans-serif; -} - -.mediumPublicSans { - font-family: PublicSans-Medium, Arial, Helvetica, serif; -} - -.item + .tooltip > .tooltip-inner { - background-color: #73ad21; - color: #ffffff; - border: 1px solid green; - padding: 5px; - font-size: 15px; - max-width: 350px; - width: 350px; -} - -.daterangepicker .ranges li { - background-color: #bfdfff; - font-size: 14px !important; - margin: 5px 2px; - border-radius: 10px; - border-color: #dddddd; - border-width: 1px; -} - -.daterangepicker .drp-selected { - font-size: 18px !important; - color: #990000; -} - -.login-link-text { - color: white; - font-size: medium; - text-decoration: none !important; -} diff --git a/apps/met-airquality/client/main.js b/apps/met-airquality/client/main.js deleted file mode 100644 index a87407a1f..000000000 --- a/apps/met-airquality/client/main.js +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. - */ - -import { matsTypes, matsCollections, methods } from "meteor/randyp:mats-common"; -import "@fortawesome/fontawesome-free"; -import "@fortawesome/fontawesome-free/css/all.css"; -import "@fortawesome/fontawesome-free/js/all.js"; diff --git a/apps/met-airquality/package-lock.json b/apps/met-airquality/package-lock.json deleted file mode 100644 index 0183ca72d..000000000 --- a/apps/met-airquality/package-lock.json +++ /dev/null @@ -1,4666 +0,0 @@ -{ - "name": "met-airquality", - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true - }, - "@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" - } - }, - "@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", - "dev": true - }, - "@babel/core": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", - "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.0", - "@babel/parser": "^7.24.0", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.0", - "@babel/types": "^7.24.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - } - }, - "@babel/eslint-parser": { - "version": "7.23.10", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.23.10.tgz", - "integrity": "sha512-3wSYDPZVnhseRnxRJH6ZVTNknBz76AEnyC+AYYhasjP3Yy23qz0ERR7Fcd2SHmYuSFJ2kY9gaaDd3vyqU09eSw==", - "dev": true, - "requires": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.1" - } - }, - "@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", - "dev": true, - "requires": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "requires": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dev": true, - "requires": { - "@babel/types": "^7.22.15" - } - }, - "@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - } - }, - "@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", - "dev": true - }, - "@babel/helpers": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.0.tgz", - "integrity": "sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==", - "dev": true, - "requires": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.0", - "@babel/types": "^7.24.0" - } - }, - "@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", - "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", - "dev": true - }, - "@babel/runtime": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", - "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", - "requires": { - "regenerator-runtime": "^0.14.0" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - } - } - }, - "@babel/template": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", - "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" - } - }, - "@babel/traverse": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz", - "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0", - "debug": "^4.3.1", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true - } - } - }, - "@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - } - } - }, - "@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true - }, - "@fortawesome/fontawesome-free": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.5.1.tgz", - "integrity": "sha512-CNy5vSwN3fsUStPRLX7fUYojyuzoEMSXPl7zSLJ8TgtRfjv24LOnOWKT2zYwaHZCJGkdyRnTmstR0P+Ah503Gw==" - }, - "@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true - }, - "@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.24.tgz", - "integrity": "sha512-+VaWXDa6+l6MhflBvVXjIEAzb59nQ2JUK3bwRp2zRpPtU+8TFRy9Gg/5oIcNlkEL5PGlBFGfemUVvIgLnTzq7Q==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", - "dev": true, - "requires": { - "eslint-scope": "5.1.1" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "@types/raf": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.0.tgz", - "integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==", - "optional": true - }, - "@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "requires": { - "dequal": "^2.0.3" - } - }, - "array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - } - }, - "array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - } - }, - "array.prototype.findlastindex": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", - "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - }, - "dependencies": { - "call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - } - }, - "get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - } - } - } - }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - } - }, - "is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "requires": { - "which-typed-array": "^1.1.11" - } - }, - "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true - }, - "regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - } - }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "dependencies": { - "call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - } - } - } - } - } - }, - "array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.tosorted": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", - "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" - } - }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - } - }, - "is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "requires": { - "which-typed-array": "^1.1.11" - } - }, - "regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - } - }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - } - } - }, - "arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "dependencies": { - "es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" - } - }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - } - }, - "is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "requires": { - "which-typed-array": "^1.1.11" - } - }, - "regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - } - }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - } - } - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" - }, - "ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true - }, - "asynciterator.prototype": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", - "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.3" - } - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true - }, - "axe-core": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", - "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", - "dev": true - }, - "axobject-query": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", - "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", - "dev": true, - "requires": { - "dequal": "^2.0.3" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bootstrap": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", - "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - } - }, - "btoa": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", - "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==" - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001591", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz", - "integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==", - "dev": true - }, - "canvg": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", - "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", - "optional": true, - "requires": { - "@babel/runtime": "^7.12.5", - "@types/raf": "^3.4.0", - "core-js": "^3.8.3", - "raf": "^3.4.1", - "regenerator-runtime": "^0.13.7", - "rgbcolor": "^1.0.1", - "stackblur-canvas": "^2.0.0", - "svg-pathdata": "^6.0.3" - } - }, - "chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "requires": { - "get-func-name": "^2.0.2" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "core-js": { - "version": "3.31.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.1.tgz", - "integrity": "sha512-2sKLtfq1eFST7l7v62zaqXacPc7uG8ZAya8ogijLhTtaKNcpzpB4TMoTw2Si+8GYKRwFPMMtUT0263QFWFfqyQ==", - "optional": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css-line-break": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", - "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", - "requires": { - "utrie": "^1.0.2" - } - }, - "damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "requires": { - "type-detect": "^4.0.0" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "define-data-property": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz", - "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - } - }, - "define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==" - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dompurify": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.5.tgz", - "integrity": "sha512-jggCCd+8Iqp4Tsz0nIvpcb22InKEBrGz5dw3EQJMs8HPJDsKbFIO3STYtAvCfDx26Muevn1MHVI0XxjgFfmiSA==", - "optional": true - }, - "downsample-lttb": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/downsample-lttb/-/downsample-lttb-0.0.1.tgz", - "integrity": "sha512-Olebo5gyh44OAXTd2BKdcbN5VaZOIKFzoeo9JUFwxDlGt6Sd8fUo6SKaLcafy8aP2UrsKmWDpsscsFEghMjeZA==" - }, - "electron-to-chromium": { - "version": "1.4.690", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.690.tgz", - "integrity": "sha512-+2OAGjUx68xElQhydpcbqH50hE8Vs2K6TkAeLhICYfndb67CVH0UsZaijmRUE3rHlIxU1u0jxwhgVe6fK3YANA==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - } - }, - "es-iterator-helpers": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", - "integrity": "sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==", - "dev": true, - "requires": { - "asynciterator.prototype": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.1", - "es-set-tostringtag": "^2.0.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.2.1", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.0.1" - }, - "dependencies": { - "define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "requires": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" - } - }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - } - }, - "is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "requires": { - "which-typed-array": "^1.1.11" - } - }, - "regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - } - }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - } - } - }, - "es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - } - }, - "es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "eslint-config-airbnb": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", - "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", - "dev": true, - "requires": { - "eslint-config-airbnb-base": "^15.0.0", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5" - } - }, - "eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "requires": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - } - }, - "eslint-config-prettier": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", - "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", - "dev": true - }, - "eslint-import-resolver-meteor": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-meteor/-/eslint-import-resolver-meteor-0.4.0.tgz", - "integrity": "sha512-BSqvgt6QZvk9EGhDGnM4azgbxyBD8b0y6FYA52WFzpWpHcZV9ys8PxM33bx8dlCy3HyopRLLsMUnlhTpZzsZmQ==", - "dev": true, - "requires": { - "object-assign": "^4.0.1", - "resolve": "^1.1.6" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "requires": { - "hasown": "^2.0.0" - } - }, - "resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "requires": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "dev": true, - "requires": { - "debug": "^3.2.7" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", - "dev": true, - "requires": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "dependencies": { - "array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - } - }, - "array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - }, - "dependencies": { - "call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - } - }, - "get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - } - } - } - }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - } - }, - "is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "requires": { - "hasown": "^2.0.0" - } - }, - "is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "requires": { - "which-typed-array": "^1.1.11" - } - }, - "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true - }, - "object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - } - }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "dependencies": { - "call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - } - } - } - } - } - }, - "eslint-plugin-jsx-a11y": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", - "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.23.2", - "aria-query": "^5.3.0", - "array-includes": "^3.1.7", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "=4.7.0", - "axobject-query": "^3.2.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "es-iterator-helpers": "^1.0.15", - "hasown": "^2.0.0", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7" - }, - "dependencies": { - "array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - } - }, - "array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, - "es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - }, - "dependencies": { - "call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - } - }, - "get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - } - } - } - }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - } - }, - "is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "requires": { - "which-typed-array": "^1.1.11" - } - }, - "jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "requires": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - } - }, - "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true - }, - "object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - } - }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "dependencies": { - "call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - } - } - } - } - } - }, - "eslint-plugin-meteor": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-meteor/-/eslint-plugin-meteor-7.3.0.tgz", - "integrity": "sha512-z+O+tZQDo9tMw4drgcDSFLpMglJCtMYA1BGX5DA2uUldQw+FPewHerZFLIQVJvSgWpQ2RC+SKaI033RhmU0d1g==", - "dev": true, - "requires": { - "invariant": "2.2.4" - } - }, - "eslint-plugin-prettier": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", - "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-plugin-react": { - "version": "7.33.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", - "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", - "dev": true, - "requires": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.12", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.8" - }, - "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "requires": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "requires": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true - } - } - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fflate": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", - "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" - }, - "fibers": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.3.tgz", - "integrity": "sha512-/qYTSoZydQkM21qZpGLDLuCq8c+B8KhuCQ1kLPvnRNhxhVbvrpmH9l2+Lblf5neDuEsY4bfT7LeO553TXQDvJw==", - "requires": { - "detect-libc": "^1.0.3" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "requires": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "requires": { - "is-callable": "^1.1.3" - } - }, - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==" - }, - "get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - } - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3" - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, - "requires": { - "function-bind": "^1.1.2" - }, - "dependencies": { - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true - } - } - }, - "html2canvas": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", - "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", - "requires": { - "css-line-break": "^2.1.0", - "text-segmentation": "^1.0.3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - } - }, - "is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true - }, - "is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dev": true, - "requires": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" - }, - "dependencies": { - "define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "requires": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - } - } - }, - "jquery": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.4.tgz", - "integrity": "sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jspdf": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz", - "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==", - "requires": { - "@babel/runtime": "^7.14.0", - "atob": "^2.1.2", - "btoa": "^1.2.1", - "canvg": "^3.0.6", - "core-js": "^3.6.0", - "dompurify": "^2.2.0", - "fflate": "^0.4.8", - "html2canvas": "^1.0.0-rc.5" - } - }, - "jsx-ast-utils": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.4.tgz", - "integrity": "sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw==", - "dev": true, - "requires": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - } - }, - "keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", - "dev": true - }, - "language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "requires": { - "language-subtag-registry": "^0.3.20" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "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 - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "requires": { - "get-func-name": "^2.0.1" - } - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true - }, - "modules": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/modules/-/modules-0.4.0.tgz", - "integrity": "sha512-LX4JgwPHJr1FurPDKp1BlGgMXqZXtxO1O8ABGmj2g15CbLGlInTHcA9flqw6uN6oYKE2T0ngWdiHvcX97mdBsw==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true - }, - "object-hash": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", - "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==" - }, - "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object-sizeof": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/object-sizeof/-/object-sizeof-1.6.3.tgz", - "integrity": "sha512-LGtilAKuDGKCcvu1Xg3UvAhAeJJlFmblo3faltmOQ80xrGwAHxnauIXucalKdTEksHp/Pq9tZGz1hfyEmjFJPQ==", - "requires": { - "buffer": "^5.6.0" - } - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - }, - "dependencies": { - "call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - } - }, - "get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - } - } - } - }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - } - }, - "is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "requires": { - "which-typed-array": "^1.1.11" - } - }, - "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true - }, - "regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - } - }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "dependencies": { - "call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "requires": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - } - } - } - } - } - }, - "object.hasown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", - "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", - "dev": true, - "requires": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" - } - }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - } - }, - "is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "requires": { - "which-typed-array": "^1.1.11" - } - }, - "regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - } - }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - } - } - }, - "object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "requires": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.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==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "optional": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "optional": true, - "requires": { - "performance-now": "^2.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "reflect.getprototypeof": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", - "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "dependencies": { - "es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" - } - }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - } - }, - "is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "requires": { - "which-typed-array": "^1.1.11" - } - }, - "regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - } - }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - } - } - }, - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "optional": true - }, - "regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" - } - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dev": true, - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rgbcolor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", - "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", - "optional": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - } - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - }, - "set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, - "requires": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "dependencies": { - "define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - } - } - } - }, - "set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, - "requires": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "stackblur-canvas": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.6.0.tgz", - "integrity": "sha512-8S1aIA+UoF6erJYnglGPug6MaHYGo1Ot7h5fuXx4fUPvcvQfcdw2o/ppCse63+eZf8PPidSu4v1JnmEVtEDnpg==", - "optional": true - }, - "string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" - }, - "dependencies": { - "es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" - }, - "dependencies": { - "regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - } - } - } - }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - } - }, - "is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "requires": { - "which-typed-array": "^1.1.11" - } - }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - } - } - }, - "string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "svg-pathdata": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", - "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", - "optional": true - }, - "text-segmentation": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", - "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", - "requires": { - "utrie": "^1.0.2" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - } - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" - } - }, - "typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - } - }, - "typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - } - }, - "typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - } - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "utrie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", - "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", - "requires": { - "base64-arraybuffer": "^1.0.2" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", - "dev": true, - "requires": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - } - }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, - "which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "xmlbuilder": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-10.1.1.tgz", - "integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "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 - } - } -} diff --git a/apps/met-airquality/package.json b/apps/met-airquality/package.json deleted file mode 100644 index 17d943c10..000000000 --- a/apps/met-airquality/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "met-airquality", - "private": true, - "scripts": { - "start": "meteor run", - "lint": "prettier --ignore-path ../../.prettierignore --check . && eslint --ignore-path ../../.gitignore .", - "format": "prettier --ignore-path ../../.prettierignore --write . && eslint --ignore-path ../../.gitignore --fix ." - }, - "dependencies": { - "@babel/runtime": "^7.24.0", - "@fortawesome/fontawesome-free": "^6.5.1", - "@popperjs/core": "^2.11.8", - "bootstrap": "^4.6.2", - "chai": "^4.4.1", - "downsample-lttb": "0.0.1", - "fibers": "^5.0.3", - "fs-extra": "^7.0.1", - "html2canvas": "^1.4.1", - "jquery": "^2.2.4", - "jspdf": "^2.5.1", - "modules": "^0.4.0", - "object-hash": "^1.3.1", - "object-sizeof": "^1.6.3", - "xmlbuilder": "^10.1.1" - }, - "devDependencies": { - "@babel/core": "^7.24.0", - "@babel/eslint-parser": "^7.23.10", - "eslint": "^8.57.0", - "eslint-config-airbnb": "^19.0.4", - "eslint-config-prettier": "^8.10.0", - "eslint-import-resolver-meteor": "^0.4.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-meteor": "^7.3.0", - "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0", - "prettier": "^2.8.8" - } -} diff --git a/apps/met-airquality/public/favicon.ico b/apps/met-airquality/public/favicon.ico deleted file mode 100755 index b14c1291a..000000000 Binary files a/apps/met-airquality/public/favicon.ico and /dev/null differ diff --git a/apps/met-airquality/public/title b/apps/met-airquality/public/title deleted file mode 100644 index bd1e85523..000000000 --- a/apps/met-airquality/public/title +++ /dev/null @@ -1 +0,0 @@ -MET Air Quality diff --git a/apps/met-airquality/server/dataFunctions/data_contour.js b/apps/met-airquality/server/dataFunctions/data_contour.js deleted file mode 100644 index 9e69fd696..000000000 --- a/apps/met-airquality/server/dataFunctions/data_contour.js +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. - */ - -import { - matsCollections, - matsTypes, - matsDataUtils, - matsDataQueryUtils, - matsDataCurveOpsUtils, - matsDataProcessUtils, -} from "meteor/randyp:mats-common"; -import { moment } from "meteor/momentjs:moment"; - -dataContour = function (plotParams, plotFunction) { - // initialize variables common to all curves - const appParams = { - plotType: matsTypes.PlotTypes.contour, - matching: plotParams.plotAction === matsTypes.PlotActions.matched, - completeness: plotParams.completeness, - outliers: plotParams.outliers, - hideGaps: plotParams.noGapsCheck, - hasLevels: true, - }; - const dataRequests = {}; // used to store data queries - let dataFoundForCurve = true; - const totalProcessingStart = moment(); - const dateRange = matsDataUtils.getDateRange(plotParams.dates); - const fromSecs = dateRange.fromSeconds; - const toSecs = dateRange.toSeconds; - const xAxisParam = plotParams["x-axis-parameter"]; - const yAxisParam = plotParams["y-axis-parameter"]; - const xValClause = matsCollections.PlotParams.findOne({ name: "x-axis-parameter" }) - .optionsMap[xAxisParam]; - const yValClause = matsCollections.PlotParams.findOne({ name: "y-axis-parameter" }) - .optionsMap[yAxisParam]; - let error = ""; - const curves = JSON.parse(JSON.stringify(plotParams.curves)); - if (curves.length > 1) { - throw new Error("INFO: There must only be one added curve."); - } - const allStatTypes = []; - const dataset = []; - const axisMap = Object.create(null); - - // initialize variables specific to the curve - const curve = curves[0]; - const { label } = curve; - const { database } = curve; - const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; - const modelClause = `and h.model = '${model}'`; - const selectorPlotType = curve["plot-type"]; - const { statistic } = curve; - const statisticOptionsMap = matsCollections.statistic.findOne( - { name: "statistic" }, - { optionsMap: 1 } - ).optionsMap[database][curve["data-source"]][selectorPlotType]; - const statLineType = statisticOptionsMap[statistic][0]; - let statisticClause = ""; - let lineDataType = ""; - if (statLineType === "scalar") { - statisticClause = - "count(ld.fbar) as n, " + - "avg(ld.fbar) as fbar, " + - "avg(ld.obar) as obar, " + - "group_concat(distinct ld.fbar, ';', ld.obar, ';', ld.ffbar, ';', ld.oobar, ';', ld.fobar, ';', " + - "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; - lineDataType = "line_data_sl1l2"; - } else if (statLineType === "ctc") { - statisticClause = - "count(ld.fy_oy) as n, " + - "sum(ld.fy_oy) as fy_oy, " + - "sum(ld.fy_on) as fy_on, " + - "sum(ld.fn_oy) as fn_oy, " + - "sum(ld.fn_on) as fn_on, " + - "group_concat(distinct ld.fy_oy, ';', ld.fy_on, ';', ld.fn_oy, ';', ld.fn_on, ';', ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; - lineDataType = "line_data_ctc"; - } - const queryTableClause = `from ${database}.stat_header h, ${database}.${lineDataType} ld`; - let regions = - curve.region === undefined || curve.region === matsTypes.InputTypes.unused - ? [] - : curve.region; - regions = Array.isArray(regions) ? regions : [regions]; - let regionsClause = ""; - if (regions.length > 0) { - regions = regions - .map(function (r) { - return `'${r}'`; - }) - .join(","); - regionsClause = `and h.vx_mask IN(${regions})`; - } - const { scale } = curve; - let scaleClause = ""; - if (scale !== "All scales") { - scaleClause = `and h.interp_pnts = '${scale}'`; - } - const im = curve["interp-method"]; - let imClause = ""; - if (im !== "All methods") { - imClause = `and h.interp_mthd = '${im}'`; - } - const { variable } = curve; - const variableValuesMap = matsCollections.variable.findOne( - { name: "variable" }, - { valuesMap: 1 } - ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; - const variableClause = `and h.fcst_var = '${variableValuesMap[variable]}'`; - const { threshold } = curve; - let thresholdClause = ""; - if (threshold !== "All thresholds") { - thresholdClause = `and h.fcst_thresh = '${threshold}'`; - } - let vts = ""; // start with an empty string that we can pass to the python script if there aren't vts. - let validTimeClause = ""; - if (xAxisParam !== "Valid UTC hour" && yAxisParam !== "Valid UTC hour") { - if ( - curve["valid-time"] !== undefined && - curve["valid-time"] !== matsTypes.InputTypes.unused - ) { - vts = curve["valid-time"]; - vts = Array.isArray(vts) ? vts : [vts]; - vts = vts - .map(function (vt) { - return `'${vt}'`; - }) - .join(","); - validTimeClause = `and unix_timestamp(ld.fcst_valid_beg)%(24*3600)/3600 IN(${vts})`; - } - } - // the forecast lengths appear to have sometimes been inconsistent (by format) in the database so they - // have been sanitized for display purposes in the forecastValueMap. - // now we have to go get the damn ole unsanitary ones for the database. - let forecastLengthsClause = ""; - if (xAxisParam !== "Fcst lead time" && yAxisParam !== "Fcst lead time") { - let fcsts = - curve["forecast-length"] === undefined || - curve["forecast-length"] === matsTypes.InputTypes.unused - ? [] - : curve["forecast-length"]; - fcsts = Array.isArray(fcsts) ? fcsts : [fcsts]; - if (fcsts.length > 0) { - fcsts = fcsts - .map(function (fl) { - return `'${fl}','${fl}0000'`; - }) - .join(","); - forecastLengthsClause = `and ld.fcst_lead IN(${fcsts})`; - } - } - let dateString = ""; - let dateClause = ""; - if ( - (xAxisParam === "Init Date" || yAxisParam === "Init Date") && - xAxisParam !== "Valid Date" && - yAxisParam !== "Valid Date" - ) { - dateString = "unix_timestamp(ld.fcst_init_beg)"; - } else { - dateString = "unix_timestamp(ld.fcst_valid_beg)"; - } - dateClause = `and ${dateString} >= ${fromSecs} and ${dateString} <= ${toSecs}`; - let levelsClause = ""; - let levels = - curve.level === undefined || curve.level === matsTypes.InputTypes.unused - ? [] - : curve.level; - levels = Array.isArray(levels) ? levels : [levels]; - if (levels.length > 0) { - levels = levels - .map(function (l) { - // sometimes bad vsdb parsing sticks an = on the end of levels in the db, so check for that. - return `'${l}','${l}='`; - }) - .join(","); - levelsClause = `and h.fcst_lev IN(${levels})`; - } else { - // we can't just leave the level clause out, because we might end up with some non-metadata-approved levels in the mix - levels = matsCollections.level.findOne({ name: "level" }, { optionsMap: 1 }) - .optionsMap[database][curve["data-source"]][selectorPlotType][statLineType][ - variable - ]; - levels = levels - .map(function (l) { - return `'${l}'`; - }) - .join(","); - levelsClause = `and h.fcst_lev IN(${levels})`; - } - let descrs = - curve.description === undefined || curve.description === matsTypes.InputTypes.unused - ? [] - : curve.description; - let descrsClause = ""; - descrs = Array.isArray(descrs) ? descrs : [descrs]; - if (descrs.length > 0) { - descrs = descrs - .map(function (d) { - return `'${d}'`; - }) - .join(","); - descrsClause = `and h.descr IN(${descrs})`; - } - appParams.aggMethod = curve["aggregation-method"]; - const statType = - curve["aggregation-method"] === "Overall statistic" && statLineType === "ctc" - ? statLineType - : `met-${statLineType}`; - allStatTypes.push(statType); - // For contours, this functions as the colorbar label. - curve.unitKey = `${variable} ${statistic}`; - - let d; - // this is a database driven curve, not a difference curve - // prepare the query from the above parameters - let statement = - "{{xValClause}} " + - "{{yValClause}} " + - "min({{dateString}}) as min_secs, " + - "max({{dateString}}) as max_secs, " + - "{{statisticClause}} " + - "{{queryTableClause}} " + - "where 1=1 " + - "{{dateClause}} " + - "{{modelClause}} " + - "{{regionsClause}} " + - "{{imClause}} " + - "{{scaleClause}} " + - "{{variableClause}} " + - "{{thresholdClause}} " + - "{{validTimeClause}} " + - "{{forecastLengthsClause}} " + - "{{levelsClause}} " + - "{{descrsClause}} " + - "and h.stat_header_id = ld.stat_header_id " + - "group by xVal,yVal " + - "order by xVal,yVal" + - ";"; - - statement = statement.replace("{{xValClause}}", xValClause); - statement = statement.replace("{{yValClause}}", yValClause); - statement = statement.replace("{{statisticClause}}", statisticClause); - statement = statement.replace("{{queryTableClause}}", queryTableClause); - statement = statement.replace("{{modelClause}}", modelClause); - statement = statement.replace("{{regionsClause}}", regionsClause); - statement = statement.replace("{{imClause}}", imClause); - statement = statement.replace("{{scaleClause}}", scaleClause); - statement = statement.replace("{{variableClause}}", variableClause); - statement = statement.replace("{{thresholdClause}}", thresholdClause); - statement = statement.replace("{{validTimeClause}}", validTimeClause); - statement = statement.replace("{{forecastLengthsClause}}", forecastLengthsClause); - statement = statement.replace("{{levelsClause}}", levelsClause); - statement = statement.replace("{{descrsClause}}", descrsClause); - statement = statement.replace("{{dateClause}}", dateClause); - statement = statement.split("{{dateString}}").join(dateString); - dataRequests[label] = statement; - - const queryArray = [ - { - statement, - statLineType, - statistic, - appParams: JSON.parse(JSON.stringify(appParams)), - fcstOffset: 0, - vts, - }, - ]; - - let queryResult; - const startMoment = moment(); - let finishMoment; - try { - // send the query statement to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); - finishMoment = moment(); - dataRequests["data retrieval (query) time"] = { - begin: startMoment.format(), - finish: finishMoment.format(), - duration: `${moment - .duration(finishMoment.diff(startMoment)) - .asSeconds()} seconds`, - recordCount: queryResult.data.length, - }; - // get the data back from the query - [d] = queryResult.data; - } catch (e) { - // this is an error produced by a bug in the query function, not an error returned by the mysql database - e.message = `Error in queryDB: ${e.message} for statement: ${statement}`; - throw new Error(e.message); - } - - // parse any errors from the python code - if (queryResult.error[0] !== undefined && queryResult.error[0] !== "") { - if (queryResult.error[0] === matsTypes.Messages.NO_DATA_FOUND) { - // this is NOT an error just a no data condition - dataFoundForCurve = false; - } else { - // this is an error returned by the mysql database - error += `Error from verification query:
${queryResult.error[0]}
query:
${statement}
`; - throw new Error(error); - } - } - - if (!dataFoundForCurve) { - // we found no data for any curves so don't bother proceeding - throw new Error("INFO: No valid data for any curves."); - } - - const postQueryStartMoment = moment(); - - // set curve annotation to be the curve mean -- may be recalculated later - // also pass previously calculated axis stats to curve options - const { mean } = d.glob_stats; - const annotation = - mean === undefined - ? `${label}- mean = NoData` - : `${label}- mean = ${mean.toPrecision(4)}`; - curve.annotation = annotation; - curve.xmin = d.xmin; - curve.xmax = d.xmax; - curve.ymin = d.ymin; - curve.ymax = d.ymax; - curve.zmin = d.zmin; - curve.zmax = d.zmax; - curve.xAxisKey = xAxisParam; - curve.yAxisKey = yAxisParam; - const cOptions = matsDataCurveOpsUtils.generateContourCurveOptions( - curve, - axisMap, - d, - appParams - ); // generate plot with data, curve annotation, axis labels, etc. - dataset.push(cOptions); - const postQueryFinishMoment = moment(); - dataRequests["post data retrieval (query) process time"] = { - begin: postQueryStartMoment.format(), - finish: postQueryFinishMoment.format(), - duration: `${moment - .duration(postQueryFinishMoment.diff(postQueryStartMoment)) - .asSeconds()} seconds`, - }; - - // process the data returned by the query - const curveInfoParams = { curve: curves, statType: allStatTypes, axisMap }; - const bookkeepingParams = { - dataRequests, - totalProcessingStart, - }; - const result = matsDataProcessUtils.processDataContour( - dataset, - curveInfoParams, - plotParams, - bookkeepingParams - ); - plotFunction(result); -}; diff --git a/apps/met-airquality/server/dataFunctions/data_dieoff.js b/apps/met-airquality/server/dataFunctions/data_dieoff.js deleted file mode 100644 index 38b7841f8..000000000 --- a/apps/met-airquality/server/dataFunctions/data_dieoff.js +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. - */ - -import { - matsCollections, - matsTypes, - matsDataUtils, - matsDataQueryUtils, - matsDataDiffUtils, - matsDataCurveOpsUtils, - matsDataProcessUtils, -} from "meteor/randyp:mats-common"; -import { moment } from "meteor/momentjs:moment"; - -dataDieoff = function (plotParams, plotFunction) { - // initialize variables common to all curves - const appParams = { - plotType: matsTypes.PlotTypes.dieoff, - matching: plotParams.plotAction === matsTypes.PlotActions.matched, - completeness: plotParams.completeness, - outliers: plotParams.outliers, - hideGaps: plotParams.noGapsCheck, - hasLevels: true, - }; - const dataRequests = {}; // used to store data queries - const queryArray = []; - const differenceArray = []; - let statement; - let dReturn; - let dataFoundForCurve = true; - let dataFoundForAnyCurve = false; - const totalProcessingStart = moment(); - let error = ""; - const curves = JSON.parse(JSON.stringify(plotParams.curves)); - const curvesLength = curves.length; - const allStatTypes = []; - const dataset = []; - const utcCycleStarts = []; - const axisMap = Object.create(null); - let xmax = -1 * Number.MAX_VALUE; - let ymax = -1 * Number.MAX_VALUE; - let xmin = Number.MAX_VALUE; - let ymin = Number.MAX_VALUE; - const idealValues = []; - - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - // initialize variables specific to each curve - const curve = curves[curveIndex]; - const { diffFrom } = curve; - const { label } = curve; - const { database } = curve; - const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; - const modelClause = `and h.model = '${model}'`; - const selectorPlotType = curve["plot-type"]; - const { statistic } = curve; - const statisticOptionsMap = matsCollections.statistic.findOne( - { name: "statistic" }, - { optionsMap: 1 } - ).optionsMap[database][curve["data-source"]][selectorPlotType]; - const statLineType = statisticOptionsMap[statistic][0]; - let statisticClause = ""; - let lineDataType = ""; - if (statLineType === "scalar") { - statisticClause = - "avg(ld.fbar) as fbar, " + - "avg(ld.obar) as obar, " + - "group_concat(distinct ld.fbar, ';', ld.obar, ';', ld.ffbar, ';', ld.oobar, ';', ld.fobar, ';', " + - "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; - lineDataType = "line_data_sl1l2"; - } else if (statLineType === "ctc") { - statisticClause = - "sum(ld.fy_oy) as fy_oy, " + - "sum(ld.fy_on) as fy_on, " + - "sum(ld.fn_oy) as fn_oy, " + - "sum(ld.fn_on) as fn_on, " + - "group_concat(distinct ld.fy_oy, ';', ld.fy_on, ';', ld.fn_oy, ';', ld.fn_on, ';', ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; - lineDataType = "line_data_ctc"; - } - const queryTableClause = `from ${database}.stat_header h, ${database}.${lineDataType} ld`; - let regions = - curve.region === undefined || curve.region === matsTypes.InputTypes.unused - ? [] - : curve.region; - regions = Array.isArray(regions) ? regions : [regions]; - let regionsClause = ""; - if (regions.length > 0) { - regions = regions - .map(function (r) { - return `'${r}'`; - }) - .join(","); - regionsClause = `and h.vx_mask IN(${regions})`; - } - const { scale } = curve; - let scaleClause = ""; - if (scale !== "All scales") { - scaleClause = `and h.interp_pnts = '${scale}'`; - } - const im = curve["interp-method"]; - let imClause = ""; - if (im !== "All methods") { - imClause = `and h.interp_mthd = '${im}'`; - } - const { variable } = curve; - const variableValuesMap = matsCollections.variable.findOne( - { name: "variable" }, - { valuesMap: 1 } - ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; - const variableClause = `and h.fcst_var = '${variableValuesMap[variable]}'`; - const { threshold } = curve; - let thresholdClause = ""; - if (threshold !== "All thresholds") { - thresholdClause = `and h.fcst_thresh = '${threshold}'`; - } - let vts = ""; // start with an empty string that we can pass to the python script if there aren't vts. - let validTimeClause = ""; - let utcCycleStart; - let utcCycleStartClause = ""; - const dieoffTypeStr = curve["dieoff-type"]; - const dieoffTypeOptionsMap = matsCollections["dieoff-type"].findOne( - { name: "dieoff-type" }, - { optionsMap: 1 } - ).optionsMap; - const dieoffType = dieoffTypeOptionsMap[dieoffTypeStr][0]; - const dateRange = matsDataUtils.getDateRange(curve["curve-dates"]); - const fromSecs = dateRange.fromSeconds; - const toSecs = dateRange.toSeconds; - let dateClause = `and unix_timestamp(ld.fcst_valid_beg) >= '${fromSecs}' and unix_timestamp(ld.fcst_valid_beg) <= '${toSecs}' `; - if (dieoffType === matsTypes.ForecastTypes.dieoff) { - vts = curve["valid-time"] === undefined ? [] : curve["valid-time"]; - if (vts.length !== 0 && vts !== matsTypes.InputTypes.unused) { - vts = curve["valid-time"]; - vts = Array.isArray(vts) ? vts : [vts]; - vts = vts - .map(function (vt) { - return `'${vt}'`; - }) - .join(","); - validTimeClause = `and unix_timestamp(ld.fcst_valid_beg)%(24*3600)/3600 IN(${vts})`; - } - } else if (dieoffType === matsTypes.ForecastTypes.utcCycle) { - utcCycleStart = - curve["utc-cycle-start"] === undefined ? [] : curve["utc-cycle-start"]; - if (utcCycleStart.length !== 0 && utcCycleStart !== matsTypes.InputTypes.unused) { - utcCycleStart = utcCycleStart - .map(function (u) { - return `'${u}'`; - }) - .join(","); - utcCycleStartClause = `and unix_timestamp(ld.fcst_init_beg)%(24*3600)/3600 IN(${utcCycleStart})`; - } - dateClause = `and unix_timestamp(ld.fcst_init_beg) >= ${fromSecs} and unix_timestamp(ld.fcst_init_beg) <= ${toSecs}`; - } else { - dateClause = `and unix_timestamp(ld.fcst_init_beg) = ${fromSecs}`; - } - let levels = - curve.level === undefined || curve.level === matsTypes.InputTypes.unused - ? [] - : curve.level; - let levelsClause = ""; - levels = Array.isArray(levels) ? levels : [levels]; - if (levels.length > 0) { - levels = levels - .map(function (l) { - // sometimes bad vsdb parsing sticks an = on the end of levels in the db, so check for that. - return `'${l}','${l}='`; - }) - .join(","); - levelsClause = `and h.fcst_lev IN(${levels})`; - } else { - // we can't just leave the level clause out, because we might end up with some non-metadata-approved levels in the mix - levels = matsCollections.level.findOne({ name: "level" }, { optionsMap: 1 }) - .optionsMap[database][curve["data-source"]][selectorPlotType][statLineType][ - variable - ]; - levels = levels - .map(function (l) { - return `'${l}'`; - }) - .join(","); - levelsClause = `and h.fcst_lev IN(${levels})`; - } - let descrs = - curve.description === undefined || - curve.description === matsTypes.InputTypes.unused - ? [] - : curve.description; - let descrsClause = ""; - descrs = Array.isArray(descrs) ? descrs : [descrs]; - if (descrs.length > 0) { - descrs = descrs - .map(function (d) { - return `'${d}'`; - }) - .join(","); - descrsClause = `and h.descr IN(${descrs})`; - } - const statType = - curve["aggregation-method"] === "Overall statistic" && statLineType === "ctc" - ? statLineType - : `met-${statLineType}`; - allStatTypes.push(statType); - appParams.aggMethod = curve["aggregation-method"]; - // axisKey is used to determine which axis a curve should use. - // This axisKeySet object is used like a set and if a curve has the same - // variable + statistic (axisKey) it will use the same axis. - // The axis number is assigned to the axisKeySet value, which is the axisKey. - const axisKey = `${variable} ${statistic}`; - curves[curveIndex].axisKey = axisKey; // stash the axisKey to use it later for axis options - - if (!diffFrom) { - // this is a database driven curve, not a difference curve - // prepare the query from the above parameters - statement = - "select ld.fcst_lead as fcst_lead, " + - "count(distinct unix_timestamp(ld.fcst_valid_beg)) as N_times, " + - "min(unix_timestamp(ld.fcst_valid_beg)) as min_secs, " + - "max(unix_timestamp(ld.fcst_valid_beg)) as max_secs, " + - "sum(ld.total) as N0, " + - "{{statisticClause}} " + - "{{queryTableClause}} " + - "where 1=1 " + - "{{dateClause}} " + - "{{modelClause}} " + - "{{regionsClause}} " + - "{{imClause}} " + - "{{scaleClause}} " + - "{{variableClause}} " + - "{{thresholdClause}} " + - "{{validTimeClause}} " + - "{{utcCycleStartClause}} " + - "{{levelsClause}} " + - "{{descrsClause}} " + - "and h.stat_header_id = ld.stat_header_id " + - "group by fcst_lead " + - "order by fcst_lead" + - ";"; - - statement = statement.replace("{{statisticClause}}", statisticClause); - statement = statement.replace("{{queryTableClause}}", queryTableClause); - statement = statement.replace("{{modelClause}}", modelClause); - statement = statement.replace("{{regionsClause}}", regionsClause); - statement = statement.replace("{{imClause}}", imClause); - statement = statement.replace("{{scaleClause}}", scaleClause); - statement = statement.replace("{{variableClause}}", variableClause); - statement = statement.replace("{{thresholdClause}}", thresholdClause); - statement = statement.replace("{{validTimeClause}}", validTimeClause); - statement = statement.replace("{{utcCycleStartClause}}", utcCycleStartClause); - statement = statement.replace("{{levelsClause}}", levelsClause); - statement = statement.replace("{{descrsClause}}", descrsClause); - statement = statement.replace("{{dateClause}}", dateClause); - dataRequests[label] = statement; - - queryArray.push({ - statement, - statLineType, - statistic, - appParams: JSON.parse(JSON.stringify(appParams)), - fcstOffset: 0, - vts, - }); - } else { - // this is a difference curve - differenceArray.push({ - dataset, - diffFrom, - appParams: JSON.parse(JSON.stringify(appParams)), - }); - } - } // end for curves - - let queryResult; - const startMoment = moment(); - let finishMoment; - try { - // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); - finishMoment = moment(); - dataRequests["data retrieval (query) time"] = { - begin: startMoment.format(), - finish: finishMoment.format(), - duration: `${moment - .duration(finishMoment.diff(startMoment)) - .asSeconds()} seconds`, - recordCount: queryResult.data.length, - }; - // get the data back from the query - dReturn = queryResult.data; - } catch (e) { - // this is an error produced by a bug in the query function, not an error returned by the mysql database - e.message = `Error in queryDB: ${e.message} for statement: ${statement}`; - throw new Error(e.message); - } - - // parse any errors from the python code - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - if ( - queryResult.error[curveIndex] !== undefined && - queryResult.error[curveIndex] !== "" - ) { - if (queryResult.error[curveIndex] === matsTypes.Messages.NO_DATA_FOUND) { - // this is NOT an error just a no data condition - dataFoundForCurve = false; - } else { - // this is an error returned by the mysql database - error += `Error from verification query:
${queryResult.error}
query:
${statement}
`; - throw new Error(error); - } - } else { - dataFoundForAnyCurve = true; - } - } - - if (!dataFoundForAnyCurve) { - // we found no data for any curves so don't bother proceeding - throw new Error("INFO: No valid data for any curves."); - } - - const postQueryStartMoment = moment(); - let d; - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - const curve = curves[curveIndex]; - if (curveIndex < dReturn.length) { - d = dReturn[curveIndex]; - // set axis limits based on returned data - if (dataFoundForCurve) { - xmin = xmin < d.xmin ? xmin : d.xmin; - xmax = xmax > d.xmax ? xmax : d.xmax; - ymin = ymin < d.ymin ? ymin : d.ymin; - ymax = ymax > d.ymax ? ymax : d.ymax; - } - } else { - const diffResult = matsDataDiffUtils.getDataForDiffCurve( - differenceArray[curveIndex - dReturn.length].dataset, - differenceArray[curveIndex - dReturn.length].diffFrom, - differenceArray[curveIndex - dReturn.length].appParams, - allStatTypes - ); - d = diffResult.dataset; - xmin = xmin < d.xmin ? xmin : d.xmin; - xmax = xmax > d.xmax ? xmax : d.xmax; - ymin = ymin < d.ymin ? ymin : d.ymin; - ymax = ymax > d.ymax ? ymax : d.ymax; - } - - // set curve annotation to be the curve mean -- may be recalculated later - // also pass previously calculated axis stats to curve options - const mean = d.sum / d.x.length; - const annotation = - mean === undefined - ? `${curve.label}- mean = NoData` - : `${curve.label}- mean = ${mean.toPrecision(4)}`; - curve.annotation = annotation; - curve.xmin = d.xmin; - curve.xmax = d.xmax; - curve.ymin = d.ymin; - curve.ymax = d.ymax; - const cOptions = matsDataCurveOpsUtils.generateSeriesCurveOptions( - curve, - curveIndex, - axisMap, - d, - appParams - ); // generate plot with data, curve annotation, axis labels, etc. - dataset.push(cOptions); - } - - // process the data returned by the query - const curveInfoParams = { - curves, - curvesLength, - idealValues, - utcCycleStarts, - statType: allStatTypes, - axisMap, - xmax, - xmin, - }; - const bookkeepingParams = { - dataRequests, - totalProcessingStart, - }; - const result = matsDataProcessUtils.processDataXYCurve( - dataset, - appParams, - curveInfoParams, - plotParams, - bookkeepingParams - ); - const postQueryFinishMoment = moment(); - dataRequests["post data retrieval (query) process time"] = { - begin: postQueryStartMoment.format(), - finish: postQueryFinishMoment.format(), - duration: `${moment - .duration(postQueryFinishMoment.diff(postQueryStartMoment)) - .asSeconds()} seconds`, - }; - plotFunction(result); -}; diff --git a/apps/met-airquality/server/dataFunctions/data_histogram.js b/apps/met-airquality/server/dataFunctions/data_histogram.js deleted file mode 100644 index 1968f85da..000000000 --- a/apps/met-airquality/server/dataFunctions/data_histogram.js +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. - */ - -import { - matsCollections, - matsTypes, - matsDataUtils, - matsDataQueryUtils, - matsDataProcessUtils, -} from "meteor/randyp:mats-common"; -import { moment } from "meteor/momentjs:moment"; - -dataHistogram = function (plotParams, plotFunction) { - // initialize variables common to all curves - const appParams = { - plotType: matsTypes.PlotTypes.histogram, - matching: plotParams.plotAction === matsTypes.PlotActions.matched, - completeness: plotParams.completeness, - outliers: plotParams.outliers, - hideGaps: plotParams.noGapsCheck, - hasLevels: true, - }; - const alreadyMatched = false; - const dataRequests = {}; // used to store data queries - const queryArray = []; - const differenceArray = []; - let statement; - let dReturn; - let dataFoundForCurve = []; - let dataFoundForAnyCurve = false; - const totalProcessingStart = moment(); - let error = ""; - const curves = JSON.parse(JSON.stringify(plotParams.curves)); - const curvesLength = curves.length; - const allStatTypes = []; - const dataset = []; - const allReturnedSubStats = []; - const allReturnedSubSecs = []; - const allReturnedSubLevs = []; - const axisMap = Object.create(null); - - // process user bin customizations - const binParams = matsDataUtils.setHistogramParameters(plotParams); - const { yAxisFormat } = binParams; - const { binNum } = binParams; - - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - // initialize variables specific to each curve - const curve = curves[curveIndex]; - const { diffFrom } = curve; - dataFoundForCurve[curveIndex] = true; - const { label } = curve; - const { database } = curve; - const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; - const modelClause = `and h.model = '${model}'`; - const selectorPlotType = curve["plot-type"]; - const { statistic } = curve; - const statisticOptionsMap = matsCollections.statistic.findOne( - { name: "statistic" }, - { optionsMap: 1 } - ).optionsMap[database][curve["data-source"]][selectorPlotType]; - const statLineType = statisticOptionsMap[statistic][0]; - let statisticClause = ""; - let lineDataType = ""; - if (statLineType === "scalar") { - statisticClause = - "avg(ld.fbar) as fbar, " + - "avg(ld.obar) as obar, " + - "group_concat(distinct ld.fbar, ';', ld.obar, ';', ld.ffbar, ';', ld.oobar, ';', ld.fobar, ';', " + - "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; - lineDataType = "line_data_sl1l2"; - } else if (statLineType === "ctc") { - statisticClause = - "sum(ld.fy_oy) as fy_oy, " + - "sum(ld.fy_on) as fy_on, " + - "sum(ld.fn_oy) as fn_oy, " + - "sum(ld.fn_on) as fn_on, " + - "group_concat(distinct ld.fy_oy, ';', ld.fy_on, ';', ld.fn_oy, ';', ld.fn_on, ';', ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; - lineDataType = "line_data_ctc"; - } - const queryTableClause = `from ${database}.stat_header h, ${database}.${lineDataType} ld`; - let regions = - curve.region === undefined || curve.region === matsTypes.InputTypes.unused - ? [] - : curve.region; - regions = Array.isArray(regions) ? regions : [regions]; - let regionsClause = ""; - if (regions.length > 0) { - regions = regions - .map(function (r) { - return `'${r}'`; - }) - .join(","); - regionsClause = `and h.vx_mask IN(${regions})`; - } - const { scale } = curve; - let scaleClause = ""; - if (scale !== "All scales") { - scaleClause = `and h.interp_pnts = '${scale}'`; - } - const im = curve["interp-method"]; - let imClause = ""; - if (im !== "All methods") { - imClause = `and h.interp_mthd = '${im}'`; - } - const { variable } = curve; - const variableValuesMap = matsCollections.variable.findOne( - { name: "variable" }, - { valuesMap: 1 } - ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; - const variableClause = `and h.fcst_var = '${variableValuesMap[variable]}'`; - const { threshold } = curve; - let thresholdClause = ""; - if (threshold !== "All thresholds") { - thresholdClause = `and h.fcst_thresh = '${threshold}'`; - } - let vts = ""; // start with an empty string that we can pass to the python script if there aren't vts. - let validTimeClause = ""; - if ( - curve["valid-time"] !== undefined && - curve["valid-time"] !== matsTypes.InputTypes.unused - ) { - vts = curve["valid-time"]; - vts = Array.isArray(vts) ? vts : [vts]; - vts = vts - .map(function (vt) { - return `'${vt}'`; - }) - .join(","); - validTimeClause = `and unix_timestamp(ld.fcst_valid_beg)%(24*3600)/3600 IN(${vts})`; - } - // the forecast lengths appear to have sometimes been inconsistent (by format) in the database so they - // have been sanitized for display purposes in the forecastValueMap. - // now we have to go get the damn ole unsanitary ones for the database. - let forecastLengthsClause = ""; - let fcsts = - curve["forecast-length"] === undefined || - curve["forecast-length"] === matsTypes.InputTypes.unused - ? [] - : curve["forecast-length"]; - fcsts = Array.isArray(fcsts) ? fcsts : [fcsts]; - if (fcsts.length > 0) { - fcsts = fcsts - .map(function (fl) { - return `'${fl}','${fl}0000'`; - }) - .join(","); - forecastLengthsClause = `and ld.fcst_lead IN(${fcsts})`; - } - const dateRange = matsDataUtils.getDateRange(curve["curve-dates"]); - const fromSecs = dateRange.fromSeconds; - const toSecs = dateRange.toSeconds; - const dateClause = `and unix_timestamp(ld.fcst_valid_beg) >= ${fromSecs} and unix_timestamp(ld.fcst_valid_beg) <= ${toSecs}`; - let levels = - curve.level === undefined || curve.level === matsTypes.InputTypes.unused - ? [] - : curve.level; - let levelsClause = ""; - levels = Array.isArray(levels) ? levels : [levels]; - if (levels.length > 0) { - levels = levels - .map(function (l) { - // sometimes bad vsdb parsing sticks an = on the end of levels in the db, so check for that. - return `'${l}','${l}='`; - }) - .join(","); - levelsClause = `and h.fcst_lev IN(${levels})`; - } else { - // we can't just leave the level clause out, because we might end up with some non-metadata-approved levels in the mix - levels = matsCollections.level.findOne({ name: "level" }, { optionsMap: 1 }) - .optionsMap[database][curve["data-source"]][selectorPlotType][statLineType][ - variable - ]; - levels = levels - .map(function (l) { - return `'${l}'`; - }) - .join(","); - levelsClause = `and h.fcst_lev IN(${levels})`; - } - let descrs = - curve.description === undefined || - curve.description === matsTypes.InputTypes.unused - ? [] - : curve.description; - let descrsClause = ""; - descrs = Array.isArray(descrs) ? descrs : [descrs]; - if (descrs.length > 0) { - descrs = descrs - .map(function (d) { - return `'${d}'`; - }) - .join(","); - descrsClause = `and h.descr IN(${descrs})`; - } - const statType = `met-${statLineType}`; - allStatTypes.push(statType); - appParams.aggMethod = "Mean statistic"; - // axisKey is used to determine which axis a curve should use. - // This axisKeySet object is used like a set and if a curve has the same - // variable (axisKey) it will use the same axis. - // Histograms should have everything under the same axisKey. - let axisKey = yAxisFormat; - if (yAxisFormat === "Relative frequency") { - axisKey += " (x100)"; - } - curves[curveIndex].axisKey = axisKey; // stash the axisKey to use it later for axis options - curves[curveIndex].binNum = binNum; // stash the binNum to use it later for bar chart options - - if (!diffFrom) { - // this is a database driven curve, not a difference curve - // prepare the query from the above parameters - statement = - "select unix_timestamp(ld.fcst_valid_beg) as avtime, " + - "count(distinct unix_timestamp(ld.fcst_valid_beg)) as N_times, " + - "min(unix_timestamp(ld.fcst_valid_beg)) as min_secs, " + - "max(unix_timestamp(ld.fcst_valid_beg)) as max_secs, " + - "sum(ld.total) as N0, " + - "{{statisticClause}} " + - "{{queryTableClause}} " + - "where 1=1 " + - "{{dateClause}} " + - "{{modelClause}} " + - "{{regionsClause}} " + - "{{imClause}} " + - "{{scaleClause}} " + - "{{variableClause}} " + - "{{thresholdClause}} " + - "{{validTimeClause}} " + - "{{forecastLengthsClause}} " + - "{{levelsClause}} " + - "{{descrsClause}} " + - "and h.stat_header_id = ld.stat_header_id " + - "group by avtime " + - "order by avtime" + - ";"; - - statement = statement.replace("{{statisticClause}}", statisticClause); - statement = statement.replace("{{queryTableClause}}", queryTableClause); - statement = statement.replace("{{modelClause}}", modelClause); - statement = statement.replace("{{regionsClause}}", regionsClause); - statement = statement.replace("{{imClause}}", imClause); - statement = statement.replace("{{scaleClause}}", scaleClause); - statement = statement.replace("{{variableClause}}", variableClause); - statement = statement.replace("{{thresholdClause}}", thresholdClause); - statement = statement.replace("{{validTimeClause}}", validTimeClause); - statement = statement.replace("{{forecastLengthsClause}}", forecastLengthsClause); - statement = statement.replace("{{levelsClause}}", levelsClause); - statement = statement.replace("{{descrsClause}}", descrsClause); - statement = statement.replace("{{dateClause}}", dateClause); - dataRequests[label] = statement; - - queryArray.push({ - statement, - statLineType, - statistic, - appParams: JSON.parse(JSON.stringify(appParams)), - fcstOffset: 0, - vts, - }); - } else { - // this is a difference curve - differenceArray.push({ - dataset, - diffFrom, - appParams: JSON.parse(JSON.stringify(appParams)), - }); - } - } // end for curves - - let queryResult; - const startMoment = moment(); - let finishMoment; - try { - // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); - finishMoment = moment(); - dataRequests["data retrieval (query) time"] = { - begin: startMoment.format(), - finish: finishMoment.format(), - duration: `${moment - .duration(finishMoment.diff(startMoment)) - .asSeconds()} seconds`, - recordCount: queryResult.data.length, - }; - // get the data back from the query - dReturn = queryResult.data; - } catch (e) { - // this is an error produced by a bug in the query function, not an error returned by the mysql database - e.message = `Error in queryDB: ${e.message} for statement: ${statement}`; - throw new Error(e.message); - } - - // parse any errors from the python code - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - if ( - queryResult.error[curveIndex] !== undefined && - queryResult.error[curveIndex] !== "" - ) { - if (queryResult.error[curveIndex] === matsTypes.Messages.NO_DATA_FOUND) { - // this is NOT an error just a no data condition - dataFoundForCurve = false; - } else { - // this is an error returned by the mysql database - error += `Error from verification query:
${queryResult.error}
query:
${statement}
`; - throw new Error(error); - } - } else { - dataFoundForAnyCurve = true; - } - } - - if (!dataFoundForAnyCurve) { - // we found no data for any curves so don't bother proceeding - throw new Error("INFO: No valid data for any curves."); - } - - const postQueryStartMoment = moment(); - let d; - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - if (curveIndex < dReturn.length) { - d = dReturn[curveIndex]; - allReturnedSubStats.push(d.subVals); // save returned data so that we can calculate histogram stats once all the queries are done - allReturnedSubSecs.push(d.subSecs); - allReturnedSubLevs.push(d.subLevs); - } - } - // process the data returned by the query - const curveInfoParams = { - curves, - curvesLength, - dataFoundForCurve, - statType: allStatTypes, - axisMap, - yAxisFormat, - varUnits: "", - }; - const bookkeepingParams = { - alreadyMatched, - dataRequests, - totalProcessingStart, - }; - const result = matsDataProcessUtils.processDataHistogram( - allReturnedSubStats, - allReturnedSubSecs, - allReturnedSubLevs, - dataset, - appParams, - curveInfoParams, - plotParams, - binParams, - bookkeepingParams - ); - const postQueryFinishMoment = moment(); - dataRequests["post data retrieval (query) process time"] = { - begin: postQueryStartMoment.format(), - finish: postQueryFinishMoment.format(), - duration: `${moment - .duration(postQueryFinishMoment.diff(postQueryStartMoment)) - .asSeconds()} seconds`, - }; - plotFunction(result); -}; diff --git a/apps/met-airquality/server/dataFunctions/data_series.js b/apps/met-airquality/server/dataFunctions/data_series.js deleted file mode 100644 index f36907141..000000000 --- a/apps/met-airquality/server/dataFunctions/data_series.js +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. - */ - -import { - matsCollections, - matsTypes, - matsDataUtils, - matsDataQueryUtils, - matsDataDiffUtils, - matsDataCurveOpsUtils, - matsDataProcessUtils, -} from "meteor/randyp:mats-common"; -import { moment } from "meteor/momentjs:moment"; - -dataSeries = function (plotParams, plotFunction) { - // initialize variables common to all curves - const appParams = { - plotType: matsTypes.PlotTypes.timeSeries, - matching: plotParams.plotAction === matsTypes.PlotActions.matched, - completeness: plotParams.completeness, - outliers: plotParams.outliers, - hideGaps: plotParams.noGapsCheck, - hasLevels: true, - }; - const dataRequests = {}; // used to store data queries - const queryArray = []; - const differenceArray = []; - let statement; - let dReturn; - let dataFoundForCurve = true; - let dataFoundForAnyCurve = false; - const totalProcessingStart = moment(); - const dateRange = matsDataUtils.getDateRange(plotParams.dates); - const fromSecs = dateRange.fromSeconds; - const toSecs = dateRange.toSeconds; - let error = ""; - const curves = JSON.parse(JSON.stringify(plotParams.curves)); - const curvesLength = curves.length; - const allStatTypes = []; - const dataset = []; - const utcCycleStarts = []; - const axisMap = Object.create(null); - let xmax = -1 * Number.MAX_VALUE; - let ymax = -1 * Number.MAX_VALUE; - let xmin = Number.MAX_VALUE; - let ymin = Number.MAX_VALUE; - const idealValues = []; - - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - // initialize variables specific to each curve - const curve = curves[curveIndex]; - const { diffFrom } = curve; - const { label } = curve; - const { database } = curve; - const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; - const modelClause = `and h.model = '${model}'`; - const selectorPlotType = curve["plot-type"]; - const { statistic } = curve; - const statisticOptionsMap = matsCollections.statistic.findOne( - { name: "statistic" }, - { optionsMap: 1 } - ).optionsMap[database][curve["data-source"]][selectorPlotType]; - const statLineType = statisticOptionsMap[statistic][0]; - let statisticClause = ""; - let lineDataType = ""; - if (statLineType === "scalar") { - statisticClause = - "avg(ld.fbar) as fbar, " + - "avg(ld.obar) as obar, " + - "group_concat(distinct ld.fbar, ';', ld.obar, ';', ld.ffbar, ';', ld.oobar, ';', ld.fobar, ';', " + - "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; - lineDataType = "line_data_sl1l2"; - } else if (statLineType === "ctc") { - statisticClause = - "sum(ld.fy_oy) as fy_oy, " + - "sum(ld.fy_on) as fy_on, " + - "sum(ld.fn_oy) as fn_oy, " + - "sum(ld.fn_on) as fn_on, " + - "group_concat(distinct ld.fy_oy, ';', ld.fy_on, ';', ld.fn_oy, ';', ld.fn_on, ';', ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; - lineDataType = "line_data_ctc"; - } - const queryTableClause = `from ${database}.stat_header h, ${database}.${lineDataType} ld`; - let regions = - curve.region === undefined || curve.region === matsTypes.InputTypes.unused - ? [] - : curve.region; - regions = Array.isArray(regions) ? regions : [regions]; - let regionsClause = ""; - if (regions.length > 0) { - regions = regions - .map(function (r) { - return `'${r}'`; - }) - .join(","); - regionsClause = `and h.vx_mask IN(${regions})`; - } - const { scale } = curve; - let scaleClause = ""; - if (scale !== "All scales") { - scaleClause = `and h.interp_pnts = '${scale}'`; - } - const im = curve["interp-method"]; - let imClause = ""; - if (im !== "All methods") { - imClause = `and h.interp_mthd = '${im}'`; - } - const { variable } = curve; - const variableValuesMap = matsCollections.variable.findOne( - { name: "variable" }, - { valuesMap: 1 } - ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; - const variableClause = `and h.fcst_var = '${variableValuesMap[variable]}'`; - const { threshold } = curve; - let thresholdClause = ""; - if (threshold !== "All thresholds") { - thresholdClause = `and h.fcst_thresh = '${threshold}'`; - } - let vts = ""; // start with an empty string that we can pass to the python script if there aren't vts. - let validTimeClause = ""; - if ( - curve["valid-time"] !== undefined && - curve["valid-time"] !== matsTypes.InputTypes.unused - ) { - vts = curve["valid-time"]; - vts = Array.isArray(vts) ? vts : [vts]; - vts = vts - .map(function (vt) { - return `'${vt}'`; - }) - .join(","); - validTimeClause = `and unix_timestamp(ld.fcst_valid_beg)%(24*3600)/3600 IN(${vts})`; - } - // the forecast lengths appear to have sometimes been inconsistent (by format) in the database so they - // have been sanitized for display purposes in the forecastValueMap. - // now we have to go get the damn ole unsanitary ones for the database. - let forecastLengthsClause = ""; - let fcsts = - curve["forecast-length"] === undefined || - curve["forecast-length"] === matsTypes.InputTypes.unused - ? [] - : curve["forecast-length"]; - fcsts = Array.isArray(fcsts) ? fcsts : [fcsts]; - const fcstOffset = fcsts[0]; - if (fcsts.length > 0) { - fcsts = fcsts - .map(function (fl) { - return `'${fl}','${fl}0000'`; - }) - .join(","); - forecastLengthsClause = `and ld.fcst_lead IN(${fcsts})`; - } - const dateClause = `and unix_timestamp(ld.fcst_valid_beg) >= ${fromSecs} and unix_timestamp(ld.fcst_valid_beg) <= ${toSecs}`; - let levels = - curve.level === undefined || curve.level === matsTypes.InputTypes.unused - ? [] - : curve.level; - let levelsClause = ""; - levels = Array.isArray(levels) ? levels : [levels]; - if (levels.length > 0) { - levels = levels - .map(function (l) { - // sometimes bad vsdb parsing sticks an = on the end of levels in the db, so check for that. - return `'${l}','${l}='`; - }) - .join(","); - levelsClause = `and h.fcst_lev IN(${levels})`; - } else { - // we can't just leave the level clause out, because we might end up with some non-metadata-approved levels in the mix - levels = matsCollections.level.findOne({ name: "level" }, { optionsMap: 1 }) - .optionsMap[database][curve["data-source"]][selectorPlotType][statLineType][ - variable - ]; - levels = levels - .map(function (l) { - return `'${l}'`; - }) - .join(","); - levelsClause = `and h.fcst_lev IN(${levels})`; - } - let descrs = - curve.description === undefined || - curve.description === matsTypes.InputTypes.unused - ? [] - : curve.description; - let descrsClause = ""; - descrs = Array.isArray(descrs) ? descrs : [descrs]; - if (descrs.length > 0) { - descrs = descrs - .map(function (d) { - return `'${d}'`; - }) - .join(","); - descrsClause = `and h.descr IN(${descrs})`; - } - const averageStr = curve.average; - const averageOptionsMap = matsCollections.average.findOne( - { name: "average" }, - { optionsMap: 1 } - ).optionsMap; - const average = averageOptionsMap[averageStr][0]; - const statType = - curve["aggregation-method"] === "Overall statistic" && statLineType === "ctc" - ? statLineType - : `met-${statLineType}`; - allStatTypes.push(statType); - appParams.aggMethod = curve["aggregation-method"]; - // axisKey is used to determine which axis a curve should use. - // This axisKeySet object is used like a set and if a curve has the same - // variable + statistic (axisKey) it will use the same axis. - // The axis number is assigned to the axisKeySet value, which is the axisKey. - const axisKey = `${variable} ${statistic}`; - curves[curveIndex].axisKey = axisKey; // stash the axisKey to use it later for axis options - - if (!diffFrom) { - // this is a database driven curve, not a difference curve - // prepare the query from the above parameters - statement = - "select {{average}} as avtime, " + - "count(distinct unix_timestamp(ld.fcst_valid_beg)) as N_times, " + - "min(unix_timestamp(ld.fcst_valid_beg)) as min_secs, " + - "max(unix_timestamp(ld.fcst_valid_beg)) as max_secs, " + - "sum(ld.total) as N0, " + - "{{statisticClause}} " + - "{{queryTableClause}} " + - "where 1=1 " + - "{{dateClause}} " + - "{{modelClause}} " + - "{{regionsClause}} " + - "{{imClause}} " + - "{{scaleClause}} " + - "{{variableClause}} " + - "{{thresholdClause}} " + - "{{validTimeClause}} " + - "{{forecastLengthsClause}} " + - "{{levelsClause}} " + - "{{descrsClause}} " + - "and h.stat_header_id = ld.stat_header_id " + - "group by avtime " + - "order by avtime" + - ";"; - - statement = statement.replace("{{average}}", average); - statement = statement.replace("{{statisticClause}}", statisticClause); - statement = statement.replace("{{queryTableClause}}", queryTableClause); - statement = statement.replace("{{modelClause}}", modelClause); - statement = statement.replace("{{regionsClause}}", regionsClause); - statement = statement.replace("{{imClause}}", imClause); - statement = statement.replace("{{scaleClause}}", scaleClause); - statement = statement.replace("{{variableClause}}", variableClause); - statement = statement.replace("{{thresholdClause}}", thresholdClause); - statement = statement.replace("{{validTimeClause}}", validTimeClause); - statement = statement.replace("{{forecastLengthsClause}}", forecastLengthsClause); - statement = statement.replace("{{levelsClause}}", levelsClause); - statement = statement.replace("{{descrsClause}}", descrsClause); - statement = statement.replace("{{dateClause}}", dateClause); - dataRequests[label] = statement; - - queryArray.push({ - statement, - statLineType, - statistic, - appParams: JSON.parse(JSON.stringify(appParams)), - fcstOffset, - vts, - }); - } else { - // this is a difference curve - differenceArray.push({ - dataset, - diffFrom, - appParams: JSON.parse(JSON.stringify(appParams)), - }); - } - } // end for curves - - let queryResult; - const startMoment = moment(); - let finishMoment; - try { - // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); - finishMoment = moment(); - dataRequests["data retrieval (query) time"] = { - begin: startMoment.format(), - finish: finishMoment.format(), - duration: `${moment - .duration(finishMoment.diff(startMoment)) - .asSeconds()} seconds`, - recordCount: queryResult.data.length, - }; - // get the data back from the query - dReturn = queryResult.data; - } catch (e) { - // this is an error produced by a bug in the query function, not an error returned by the mysql database - e.message = `Error in queryDB: ${e.message} for statement: ${statement}`; - throw new Error(e.message); - } - - // parse any errors from the python code - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - if ( - queryResult.error[curveIndex] !== undefined && - queryResult.error[curveIndex] !== "" - ) { - if (queryResult.error[curveIndex] === matsTypes.Messages.NO_DATA_FOUND) { - // this is NOT an error just a no data condition - dataFoundForCurve = false; - } else { - // this is an error returned by the mysql database - error += `Error from verification query:
${queryResult.error}
query:
${statement}
`; - throw new Error(error); - } - } else { - dataFoundForAnyCurve = true; - } - } - - if (!dataFoundForAnyCurve) { - // we found no data for any curves so don't bother proceeding - throw new Error("INFO: No valid data for any curves."); - } - - const postQueryStartMoment = moment(); - let d; - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - const curve = curves[curveIndex]; - if (curveIndex < dReturn.length) { - d = dReturn[curveIndex]; - // set axis limits based on returned data - if (dataFoundForCurve) { - xmin = xmin < d.xmin ? xmin : d.xmin; - xmax = xmax > d.xmax ? xmax : d.xmax; - ymin = ymin < d.ymin ? ymin : d.ymin; - ymax = ymax > d.ymax ? ymax : d.ymax; - } - } else { - const diffResult = matsDataDiffUtils.getDataForDiffCurve( - differenceArray[curveIndex - dReturn.length].dataset, - differenceArray[curveIndex - dReturn.length].diffFrom, - differenceArray[curveIndex - dReturn.length].appParams, - allStatTypes - ); - d = diffResult.dataset; - xmin = xmin < d.xmin ? xmin : d.xmin; - xmax = xmax > d.xmax ? xmax : d.xmax; - ymin = ymin < d.ymin ? ymin : d.ymin; - ymax = ymax > d.ymax ? ymax : d.ymax; - } - - // set curve annotation to be the curve mean -- may be recalculated later - // also pass previously calculated axis stats to curve options - const mean = d.sum / d.x.length; - const annotation = - mean === undefined - ? `${curve.label}- mean = NoData` - : `${curve.label}- mean = ${mean.toPrecision(4)}`; - curve.annotation = annotation; - curve.xmin = d.xmin; - curve.xmax = d.xmax; - curve.ymin = d.ymin; - curve.ymax = d.ymax; - const cOptions = matsDataCurveOpsUtils.generateSeriesCurveOptions( - curve, - curveIndex, - axisMap, - d, - appParams - ); // generate plot with data, curve annotation, axis labels, etc. - dataset.push(cOptions); - } - - // process the data returned by the query - const curveInfoParams = { - curves, - curvesLength, - idealValues, - utcCycleStarts, - statType: allStatTypes, - axisMap, - xmax, - xmin, - }; - const bookkeepingParams = { - dataRequests, - totalProcessingStart, - }; - const result = matsDataProcessUtils.processDataXYCurve( - dataset, - appParams, - curveInfoParams, - plotParams, - bookkeepingParams - ); - const postQueryFinishMoment = moment(); - dataRequests["post data retrieval (query) process time"] = { - begin: postQueryStartMoment.format(), - finish: postQueryFinishMoment.format(), - duration: `${moment - .duration(postQueryFinishMoment.diff(postQueryStartMoment)) - .asSeconds()} seconds`, - }; - plotFunction(result); -}; diff --git a/apps/met-airquality/server/dataFunctions/data_simple_scatter.js b/apps/met-airquality/server/dataFunctions/data_simple_scatter.js deleted file mode 100644 index fa08d8b55..000000000 --- a/apps/met-airquality/server/dataFunctions/data_simple_scatter.js +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. - */ - -import { - matsCollections, - matsTypes, - matsDataUtils, - matsDataQueryUtils, - matsDataCurveOpsUtils, - matsDataProcessUtils, -} from "meteor/randyp:mats-common"; -import { moment } from "meteor/momentjs:moment"; - -dataSimpleScatter = function (plotParams, plotFunction) { - // initialize variables common to all curves - const appParams = { - plotType: matsTypes.PlotTypes.simpleScatter, - matching: plotParams.plotAction === matsTypes.PlotActions.matched, - completeness: plotParams.completeness, - outliers: plotParams.outliers, - hideGaps: plotParams.noGapsCheck, - hasLevels: true, - }; - const dataRequests = {}; // used to store data queries - const queryArray = []; - let statement; - let dReturn; - let dataFoundForCurve = true; - let dataFoundForAnyCurve = false; - const totalProcessingStart = moment(); - let error = ""; - const curves = JSON.parse(JSON.stringify(plotParams.curves)); - const curvesLength = curves.length; - const allStatTypes = []; - const dataset = []; - const axisXMap = Object.create(null); - const axisYMap = Object.create(null); - let xmax = -1 * Number.MAX_VALUE; - let ymax = -1 * Number.MAX_VALUE; - let xmin = Number.MAX_VALUE; - let ymin = Number.MAX_VALUE; - - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - // initialize variables specific to each curve - const curve = curves[curveIndex]; - const { diffFrom } = curve; - const { label } = curve; - const { database } = curve; - const binParam = curve["bin-parameter"]; - const binClause = matsCollections["bin-parameter"].findOne({ - name: "bin-parameter", - }).optionsMap[binParam]; - const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; - const modelClause = `and h.model = '${model}'`; - const selectorPlotType = curve["plot-type"]; - const statisticXSelect = curve.statistic; - const statisticYSelect = curve["y-statistic"]; - const statisticOptionsMap = matsCollections.statistic.findOne( - { name: "statistic" }, - { optionsMap: 1 } - ).optionsMap[database][curve["data-source"]][selectorPlotType]; - const statLineType = statisticOptionsMap[statisticXSelect][0]; - let statisticClauseX = ""; - let statisticClauseY = ""; - let lineDataType = ""; - if (statLineType === "scalar") { - statisticClauseX = - "count(ld.fbar) as nX, " + - "avg(ld.fbar) as fbarX, " + - "avg(ld.obar) as obarX, " + - "group_concat(distinct ld.fbar, ';', ld.obar, ';', ld.ffbar, ';', ld.oobar, ';', ld.fobar, ';', " + - "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_dataX"; - statisticClauseY = - "count(ld.fbar) as nY, " + - "avg(ld.fbar) as fbarY, " + - "avg(ld.obar) as obarY, " + - "group_concat(distinct ld.fbar, ';', ld.obar, ';', ld.ffbar, ';', ld.oobar, ';', ld.fobar, ';', " + - "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_dataY"; - lineDataType = "line_data_sl1l2"; - } - const queryTableClause = `from ${database}.stat_header h, ${database}.${lineDataType} ld`; - let regions = - curve.region === undefined || curve.region === matsTypes.InputTypes.unused - ? [] - : curve.region; - regions = Array.isArray(regions) ? regions : [regions]; - let regionsClause = ""; - if (regions.length > 0) { - regions = regions - .map(function (r) { - return `'${r}'`; - }) - .join(","); - regionsClause = `and h.vx_mask IN(${regions})`; - } - const { scale } = curve; - let scaleClause = ""; - if (scale !== "All scales") { - scaleClause = `and h.interp_pnts = '${scale}'`; - } - const im = curve["interp-method"]; - let imClause = ""; - if (im !== "All methods") { - imClause = `and h.interp_mthd = '${im}'`; - } - const variableXStr = curve.variable; - const variableYStr = curve["y-variable"]; - const variableValuesMap = matsCollections.variable.findOne( - { name: "variable" }, - { valuesMap: 1 } - ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; - const variableX = variableValuesMap[variableXStr]; - const variableY = variableValuesMap[variableYStr]; - const variableClauseX = `and h.fcst_var = '${variableValuesMap[variableX]}'`; - const variableClauseY = `and h.fcst_var = '${variableValuesMap[variableY]}'`; - const dateRange = matsDataUtils.getDateRange(curve["curve-dates"]); - const fromSecs = dateRange.fromSeconds; - const toSecs = dateRange.toSeconds; - const { threshold } = curve; - let thresholdClause = ""; - if (threshold !== "All thresholds") { - thresholdClause = `and h.fcst_thresh = '${threshold}'`; - } - let vts = ""; // start with an empty string that we can pass to the python script if there aren't vts. - let validTimeClause = ""; - if (binParam !== "Valid UTC hour") { - if ( - curve["valid-time"] !== undefined && - curve["valid-time"] !== matsTypes.InputTypes.unused - ) { - vts = curve["valid-time"]; - vts = Array.isArray(vts) ? vts : [vts]; - vts = vts - .map(function (vt) { - return `'${vt}'`; - }) - .join(","); - validTimeClause = `and unix_timestamp(ld.fcst_valid_beg)%(24*3600)/3600 IN(${vts})`; - } - } - // the forecast lengths appear to have sometimes been inconsistent (by format) in the database so they - // have been sanitized for display purposes in the forecastValueMap. - // now we have to go get the damn ole unsanitary ones for the database. - let forecastLengthsClause = ""; - if (binParam !== "Fcst lead time") { - let fcsts = - curve["forecast-length"] === undefined || - curve["forecast-length"] === matsTypes.InputTypes.unused - ? [] - : curve["forecast-length"]; - fcsts = Array.isArray(fcsts) ? fcsts : [fcsts]; - if (fcsts.length > 0) { - fcsts = fcsts - .map(function (fl) { - return `'${fl}','${fl}0000'`; - }) - .join(","); - forecastLengthsClause = `and ld.fcst_lead IN(${fcsts})`; - } - } - let dateString = ""; - let dateClause = ""; - if (binParam === "Init Date" && binParam !== "Valid Date") { - dateString = "unix_timestamp(ld.fcst_init_beg)"; - } else { - dateString = "unix_timestamp(ld.fcst_valid_beg)"; - } - dateClause = `and ${dateString} >= ${fromSecs} and ${dateString} <= ${toSecs}`; - let levels = - curve.level === undefined || curve.level === matsTypes.InputTypes.unused - ? [] - : curve.level; - levels = Array.isArray(levels) ? levels : [levels]; - if (binParam !== "Pressure level" && levels.length > 0) { - levels = levels - .map(function (l) { - // sometimes bad vsdb parsing sticks an = on the end of levels in the db, so check for that. - return `'${l}','${l}='`; - }) - .join(","); - } else { - // we can't just leave the level clause out, because we might end up with some non-metadata-approved levels in the mix - levels = matsCollections.level.findOne({ name: "level" }, { optionsMap: 1 }) - .optionsMap[database][curve["data-source"]][selectorPlotType][statLineType][ - variableX - ]; - levels = levels - .map(function (l) { - return `'${l}'`; - }) - .join(","); - } - const levelsClause = `and h.fcst_lev IN(${levels})`; - let descrs = - curve.description === undefined || - curve.description === matsTypes.InputTypes.unused - ? [] - : curve.description; - let descrsClause = ""; - descrs = Array.isArray(descrs) ? descrs : [descrs]; - if (descrs.length > 0) { - descrs = descrs - .map(function (d) { - return `'${d}'`; - }) - .join(","); - descrsClause = `and h.descr IN(${descrs})`; - } - appParams.aggMethod = curve["aggregation-method"]; - const statType = - curve["aggregation-method"] === "Overall statistic" && statLineType === "ctc" - ? statLineType - : `met-${statLineType}`; - allStatTypes.push(statType); - curves[curveIndex].axisXKey = `${variableXStr} ${statisticXSelect}`; // stash the axisKey to use it later for axis options - curves[curveIndex].axisYKey = `${variableYStr} ${statisticYSelect}`; // stash the axisKey to use it later for axis options - curves[curveIndex].binParam = binParam; // stash the binParam to use it later for axis options - - if (!diffFrom) { - // this is a database driven curve, not a difference curve - // prepare the query from the above parameters - statement = - "{{binClause}} " + - "min({{dateString}}) as min_secs, " + - "max({{dateString}}) as max_secs, " + - "{{statisticClause}} " + - "{{queryTableClause}} " + - "where 1=1 " + - "{{dateClause}} " + - "{{modelClause}} " + - "{{regionsClause}} " + - "{{imClause}} " + - "{{scaleClause}} " + - "{{variableClause}} " + - "{{thresholdClause}} " + - "{{validTimeClause}} " + - "{{forecastLengthsClause}} " + - "{{levelsClause}} " + - "{{descrsClause}} " + - "and h.stat_header_id = ld.stat_header_id " + - "group by binVal " + - "order by binVal" + - ";"; - - statement = statement.replace("{{binClause}}", binClause); - statement = statement.replace("{{queryTableClause}}", queryTableClause); - statement = statement.replace("{{modelClause}}", modelClause); - statement = statement.replace("{{regionsClause}}", regionsClause); - statement = statement.replace("{{imClause}}", imClause); - statement = statement.replace("{{scaleClause}}", scaleClause); - statement = statement.replace("{{thresholdClause}}", thresholdClause); - statement = statement.replace("{{validTimeClause}}", validTimeClause); - statement = statement.replace("{{forecastLengthsClause}}", forecastLengthsClause); - statement = statement.replace("{{levelsClause}}", levelsClause); - statement = statement.replace("{{descrsClause}}", descrsClause); - statement = statement.replace("{{dateClause}}", dateClause); - statement = statement.split("{{dateString}}").join(dateString); - - let statement1 = statement.replace("{{statisticClause}}", statisticClauseX); - statement1 = statement1.replace("{{variableClause}}", variableClauseX); - let statement2 = statement.replace("{{statisticClause}}", statisticClauseY); - statement2 = statement2.replace("{{variableClause}}", variableClauseY); - - dataRequests[label] = statement; - - queryArray.push({ - statement: [statement1, statement2], - statLineType, - statistic: `${statisticXSelect}__vs__${statisticYSelect}`, - appParams: JSON.parse(JSON.stringify(appParams)), - fcstOffset: 0, - vts, - }); - } else { - // this is a difference curve -- not supported for scatter plots - throw new Error( - "INFO: Difference curves are not supported for performance diagrams, as they do not feature consistent x or y values across all curves." - ); - } - } // end for curves - - let queryResult; - const startMoment = moment(); - let finishMoment; - try { - // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); - finishMoment = moment(); - dataRequests["data retrieval (query) time"] = { - begin: startMoment.format(), - finish: finishMoment.format(), - duration: `${moment - .duration(finishMoment.diff(startMoment)) - .asSeconds()} seconds`, - recordCount: queryResult.data.length, - }; - // get the data back from the query - dReturn = queryResult.data; - } catch (e) { - // this is an error produced by a bug in the query function, not an error returned by the mysql database - e.message = `Error in queryDB: ${e.message} for statement: ${statement}`; - throw new Error(e.message); - } - - // parse any errors from the python code - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - if ( - queryResult.error[curveIndex] !== undefined && - queryResult.error[curveIndex] !== "" - ) { - if (queryResult.error[curveIndex] === matsTypes.Messages.NO_DATA_FOUND) { - // this is NOT an error just a no data condition - dataFoundForCurve = false; - } else { - // this is an error returned by the mysql database - error += `Error from verification query:
${queryResult.error}
query:
${statement}
`; - throw new Error(error); - } - } else { - dataFoundForAnyCurve = true; - } - } - - if (!dataFoundForAnyCurve) { - // we found no data for any curves so don't bother proceeding - throw new Error("INFO: No valid data for any curves."); - } - - const postQueryStartMoment = moment(); - let d; - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - const curve = curves[curveIndex]; - d = dReturn[curveIndex]; - // set axis limits based on returned data - if (dataFoundForCurve) { - xmin = xmin < d.xmin ? xmin : d.xmin; - xmax = xmax > d.xmax ? xmax : d.xmax; - ymin = ymin < d.ymin ? ymin : d.ymin; - ymax = ymax > d.ymax ? ymax : d.ymax; - } - - // set curve annotation to be the curve mean -- may be recalculated later - // also pass previously calculated axis stats to curve options - const mean = d.sum / d.x.length; - const annotation = - mean === undefined - ? `${curve.label}- mean = NoData` - : `${curve.label}- mean = ${mean.toPrecision(4)}`; - curve.annotation = annotation; - curve.xmin = d.xmin; - curve.xmax = d.xmax; - curve.ymin = d.ymin; - curve.ymax = d.ymax; - const cOptions = matsDataCurveOpsUtils.generateScatterCurveOptions( - curve, - curveIndex, - axisXMap, - axisYMap, - d, - appParams - ); // generate plot with data, curve annotation, axis labels, etc. - dataset.push(cOptions); - } - - // process the data returned by the query - const curveInfoParams = { - curves, - curvesLength, - statType: allStatTypes, - axisXMap, - axisYMap, - xmax, - xmin, - }; - const bookkeepingParams = { - dataRequests, - totalProcessingStart, - }; - const result = matsDataProcessUtils.processDataSimpleScatter( - dataset, - appParams, - curveInfoParams, - plotParams, - bookkeepingParams - ); - const postQueryFinishMoment = moment(); - dataRequests["post data retrieval (query) process time"] = { - begin: postQueryStartMoment.format(), - finish: postQueryFinishMoment.format(), - duration: `${moment - .duration(postQueryFinishMoment.diff(postQueryStartMoment)) - .asSeconds()} seconds`, - }; - plotFunction(result); -}; diff --git a/apps/met-airquality/server/dataFunctions/data_validtime.js b/apps/met-airquality/server/dataFunctions/data_validtime.js deleted file mode 100644 index fc800f4d1..000000000 --- a/apps/met-airquality/server/dataFunctions/data_validtime.js +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. - */ - -import { - matsCollections, - matsTypes, - matsDataUtils, - matsDataQueryUtils, - matsDataDiffUtils, - matsDataCurveOpsUtils, - matsDataProcessUtils, -} from "meteor/randyp:mats-common"; -import { moment } from "meteor/momentjs:moment"; - -dataValidTime = function (plotParams, plotFunction) { - // initialize variables common to all curves - const appParams = { - plotType: matsTypes.PlotTypes.validtime, - matching: plotParams.plotAction === matsTypes.PlotActions.matched, - completeness: plotParams.completeness, - outliers: plotParams.outliers, - hideGaps: plotParams.noGapsCheck, - hasLevels: true, - }; - const dataRequests = {}; // used to store data queries - const queryArray = []; - const differenceArray = []; - let statement; - let dReturn; - let dataFoundForCurve = true; - let dataFoundForAnyCurve = false; - const totalProcessingStart = moment(); - let error = ""; - const curves = JSON.parse(JSON.stringify(plotParams.curves)); - const curvesLength = curves.length; - const allStatTypes = []; - const dataset = []; - const utcCycleStarts = []; - const axisMap = Object.create(null); - let xmax = -1 * Number.MAX_VALUE; - let ymax = -1 * Number.MAX_VALUE; - let xmin = Number.MAX_VALUE; - let ymin = Number.MAX_VALUE; - const idealValues = []; - - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - // initialize variables specific to each curve - const curve = curves[curveIndex]; - const { diffFrom } = curve; - const { label } = curve; - const { database } = curve; - const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; - const modelClause = `and h.model = '${model}'`; - const selectorPlotType = curve["plot-type"]; - const { statistic } = curve; - const statisticOptionsMap = matsCollections.statistic.findOne( - { name: "statistic" }, - { optionsMap: 1 } - ).optionsMap[database][curve["data-source"]][selectorPlotType]; - const statLineType = statisticOptionsMap[statistic][0]; - let statisticClause = ""; - let lineDataType = ""; - if (statLineType === "scalar") { - statisticClause = - "avg(ld.fbar) as fbar, " + - "avg(ld.obar) as obar, " + - "group_concat(distinct ld.fbar, ';', ld.obar, ';', ld.ffbar, ';', ld.oobar, ';', ld.fobar, ';', " + - "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; - lineDataType = "line_data_sl1l2"; - } else if (statLineType === "ctc") { - statisticClause = - "sum(ld.fy_oy) as fy_oy, " + - "sum(ld.fy_on) as fy_on, " + - "sum(ld.fn_oy) as fn_oy, " + - "sum(ld.fn_on) as fn_on, " + - "group_concat(distinct ld.fy_oy, ';', ld.fy_on, ';', ld.fn_oy, ';', ld.fn_on, ';', ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; - lineDataType = "line_data_ctc"; - } - const queryTableClause = `from ${database}.stat_header h, ${database}.${lineDataType} ld`; - let regions = - curve.region === undefined || curve.region === matsTypes.InputTypes.unused - ? [] - : curve.region; - regions = Array.isArray(regions) ? regions : [regions]; - let regionsClause = ""; - if (regions.length > 0) { - regions = regions - .map(function (r) { - return `'${r}'`; - }) - .join(","); - regionsClause = `and h.vx_mask IN(${regions})`; - } - const { scale } = curve; - let scaleClause = ""; - if (scale !== "All scales") { - scaleClause = `and h.interp_pnts = '${scale}'`; - } - const im = curve["interp-method"]; - let imClause = ""; - if (im !== "All methods") { - imClause = `and h.interp_mthd = '${im}'`; - } - const { variable } = curve; - const variableValuesMap = matsCollections.variable.findOne( - { name: "variable" }, - { valuesMap: 1 } - ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; - const variableClause = `and h.fcst_var = '${variableValuesMap[variable]}'`; - const { threshold } = curve; - let thresholdClause = ""; - if (threshold !== "All thresholds") { - thresholdClause = `and h.fcst_thresh = '${threshold}'`; - } - const vts = ""; // have an empty string that we can pass to the python script. - // the forecast lengths appear to have sometimes been inconsistent (by format) in the database so they - // have been sanitized for display purposes in the forecastValueMap. - // now we have to go get the damn ole unsanitary ones for the database. - let forecastLengthsClause = ""; - let fcsts = - curve["forecast-length"] === undefined || - curve["forecast-length"] === matsTypes.InputTypes.unused - ? [] - : curve["forecast-length"]; - fcsts = Array.isArray(fcsts) ? fcsts : [fcsts]; - if (fcsts.length > 0) { - fcsts = fcsts - .map(function (fl) { - return `'${fl}','${fl}0000'`; - }) - .join(","); - forecastLengthsClause = `and ld.fcst_lead IN(${fcsts})`; - } - const dateRange = matsDataUtils.getDateRange(curve["curve-dates"]); - const fromSecs = dateRange.fromSeconds; - const toSecs = dateRange.toSeconds; - const dateClause = `and unix_timestamp(ld.fcst_valid_beg) >= ${fromSecs} and unix_timestamp(ld.fcst_valid_beg) <= ${toSecs}`; - let levels = - curve.level === undefined || curve.level === matsTypes.InputTypes.unused - ? [] - : curve.level; - let levelsClause = ""; - levels = Array.isArray(levels) ? levels : [levels]; - if (levels.length > 0) { - levels = levels - .map(function (l) { - // sometimes bad vsdb parsing sticks an = on the end of levels in the db, so check for that. - return `'${l}','${l}='`; - }) - .join(","); - levelsClause = `and h.fcst_lev IN(${levels})`; - } else { - // we can't just leave the level clause out, because we might end up with some non-metadata-approved levels in the mix - levels = matsCollections.level.findOne({ name: "level" }, { optionsMap: 1 }) - .optionsMap[database][curve["data-source"]][selectorPlotType][statLineType][ - variable - ]; - levels = levels - .map(function (l) { - return `'${l}'`; - }) - .join(","); - levelsClause = `and h.fcst_lev IN(${levels})`; - } - let descrs = - curve.description === undefined || - curve.description === matsTypes.InputTypes.unused - ? [] - : curve.description; - let descrsClause = ""; - descrs = Array.isArray(descrs) ? descrs : [descrs]; - if (descrs.length > 0) { - descrs = descrs - .map(function (d) { - return `'${d}'`; - }) - .join(","); - descrsClause = `and h.descr IN(${descrs})`; - } - const statType = - curve["aggregation-method"] === "Overall statistic" && statLineType === "ctc" - ? statLineType - : `met-${statLineType}`; - allStatTypes.push(statType); - appParams.aggMethod = curve["aggregation-method"]; - // axisKey is used to determine which axis a curve should use. - // This axisKeySet object is used like a set and if a curve has the same - // variable + statistic (axisKey) it will use the same axis. - // The axis number is assigned to the axisKeySet value, which is the axisKey. - const axisKey = `${variable} ${statistic}`; - curves[curveIndex].axisKey = axisKey; // stash the axisKey to use it later for axis options - - if (!diffFrom) { - // this is a database driven curve, not a difference curve - // prepare the query from the above parameters - statement = - "select unix_timestamp(ld.fcst_valid_beg)%(24*3600)/3600 as hr_of_day, " + - "count(distinct unix_timestamp(ld.fcst_valid_beg)) as N_times, " + - "min(unix_timestamp(ld.fcst_valid_beg)) as min_secs, " + - "max(unix_timestamp(ld.fcst_valid_beg)) as max_secs, " + - "sum(ld.total) as N0, " + - "{{statisticClause}} " + - "{{queryTableClause}} " + - "where 1=1 " + - "{{dateClause}} " + - "{{modelClause}} " + - "{{regionsClause}} " + - "{{imClause}} " + - "{{scaleClause}} " + - "{{variableClause}} " + - "{{thresholdClause}} " + - "{{forecastLengthsClause}} " + - "{{levelsClause}} " + - "{{descrsClause}} " + - "and h.stat_header_id = ld.stat_header_id " + - "group by hr_of_day " + - "order by hr_of_day" + - ";"; - - statement = statement.replace("{{statisticClause}}", statisticClause); - statement = statement.replace("{{queryTableClause}}", queryTableClause); - statement = statement.replace("{{modelClause}}", modelClause); - statement = statement.replace("{{regionsClause}}", regionsClause); - statement = statement.replace("{{imClause}}", imClause); - statement = statement.replace("{{scaleClause}}", scaleClause); - statement = statement.replace("{{variableClause}}", variableClause); - statement = statement.replace("{{thresholdClause}}", thresholdClause); - statement = statement.replace("{{forecastLengthsClause}}", forecastLengthsClause); - statement = statement.replace("{{levelsClause}}", levelsClause); - statement = statement.replace("{{descrsClause}}", descrsClause); - statement = statement.replace("{{dateClause}}", dateClause); - dataRequests[label] = statement; - - queryArray.push({ - statement, - statLineType, - statistic, - appParams: JSON.parse(JSON.stringify(appParams)), - fcstOffset: 0, - vts, - }); - } else { - // this is a difference curve - differenceArray.push({ - dataset, - diffFrom, - appParams: JSON.parse(JSON.stringify(appParams)), - }); - } - } // end for curves - - let queryResult; - const startMoment = moment(); - let finishMoment; - try { - // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); - finishMoment = moment(); - dataRequests["data retrieval (query) time"] = { - begin: startMoment.format(), - finish: finishMoment.format(), - duration: `${moment - .duration(finishMoment.diff(startMoment)) - .asSeconds()} seconds`, - recordCount: queryResult.data.length, - }; - // get the data back from the query - dReturn = queryResult.data; - } catch (e) { - // this is an error produced by a bug in the query function, not an error returned by the mysql database - e.message = `Error in queryDB: ${e.message} for statement: ${statement}`; - throw new Error(e.message); - } - - // parse any errors from the python code - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - if ( - queryResult.error[curveIndex] !== undefined && - queryResult.error[curveIndex] !== "" - ) { - if (queryResult.error[curveIndex] === matsTypes.Messages.NO_DATA_FOUND) { - // this is NOT an error just a no data condition - dataFoundForCurve = false; - } else { - // this is an error returned by the mysql database - error += `Error from verification query:
${queryResult.error}
query:
${statement}
`; - throw new Error(error); - } - } else { - dataFoundForAnyCurve = true; - } - } - - if (!dataFoundForAnyCurve) { - // we found no data for any curves so don't bother proceeding - throw new Error("INFO: No valid data for any curves."); - } - - const postQueryStartMoment = moment(); - let d; - for (let curveIndex = 0; curveIndex < curvesLength; curveIndex += 1) { - const curve = curves[curveIndex]; - if (curveIndex < dReturn.length) { - d = dReturn[curveIndex]; - // set axis limits based on returned data - if (dataFoundForCurve) { - xmin = xmin < d.xmin ? xmin : d.xmin; - xmax = xmax > d.xmax ? xmax : d.xmax; - ymin = ymin < d.ymin ? ymin : d.ymin; - ymax = ymax > d.ymax ? ymax : d.ymax; - } - } else { - const diffResult = matsDataDiffUtils.getDataForDiffCurve( - differenceArray[curveIndex - dReturn.length].dataset, - differenceArray[curveIndex - dReturn.length].diffFrom, - differenceArray[curveIndex - dReturn.length].appParams, - allStatTypes - ); - d = diffResult.dataset; - xmin = xmin < d.xmin ? xmin : d.xmin; - xmax = xmax > d.xmax ? xmax : d.xmax; - ymin = ymin < d.ymin ? ymin : d.ymin; - ymax = ymax > d.ymax ? ymax : d.ymax; - } - - // set curve annotation to be the curve mean -- may be recalculated later - // also pass previously calculated axis stats to curve options - const mean = d.sum / d.x.length; - const annotation = - mean === undefined - ? `${curve.label}- mean = NoData` - : `${curve.label}- mean = ${mean.toPrecision(4)}`; - curve.annotation = annotation; - curve.xmin = d.xmin; - curve.xmax = d.xmax; - curve.ymin = d.ymin; - curve.ymax = d.ymax; - const cOptions = matsDataCurveOpsUtils.generateSeriesCurveOptions( - curve, - curveIndex, - axisMap, - d, - appParams - ); // generate plot with data, curve annotation, axis labels, etc. - dataset.push(cOptions); - } - - // process the data returned by the query - const curveInfoParams = { - curves, - curvesLength, - idealValues, - utcCycleStarts, - statType: allStatTypes, - axisMap, - xmax, - xmin, - }; - const bookkeepingParams = { - dataRequests, - totalProcessingStart, - }; - const result = matsDataProcessUtils.processDataXYCurve( - dataset, - appParams, - curveInfoParams, - plotParams, - bookkeepingParams - ); - const postQueryFinishMoment = moment(); - dataRequests["post data retrieval (query) process time"] = { - begin: postQueryStartMoment.format(), - finish: postQueryFinishMoment.format(), - duration: `${moment - .duration(postQueryFinishMoment.diff(postQueryStartMoment)) - .asSeconds()} seconds`, - }; - plotFunction(result); -}; diff --git a/apps/met-airquality/server/main.js b/apps/met-airquality/server/main.js deleted file mode 100644 index 10432d46a..000000000 --- a/apps/met-airquality/server/main.js +++ /dev/null @@ -1,2287 +0,0 @@ -/* - * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. - */ - -import { Meteor } from "meteor/meteor"; -import { mysql } from "meteor/pcel:mysql"; -import { moment } from "meteor/momentjs:moment"; -import { _ } from "meteor/underscore"; -import { - matsMethods, - matsTypes, - matsCollections, - matsDataUtils, - matsDataQueryUtils, - matsParamUtils, -} from "meteor/randyp:mats-common"; - -// determined in doCurveParanms -let minDate; -let maxDate; -let dstr; - -const doPlotParams = function () { - if ( - matsCollections.Settings.findOne({}) === undefined || - matsCollections.Settings.findOne({}).resetFromCode === undefined || - matsCollections.Settings.findOne({}).resetFromCode === true - ) { - matsCollections.PlotParams.remove({}); - } - if (matsCollections.PlotParams.find().count() === 0) { - matsCollections.PlotParams.insert({ - name: "dates", - type: matsTypes.InputTypes.dateRange, - options: [""], - startDate: minDate, - stopDate: maxDate, - superiorNames: ["database", "data-source", "plot-type", "statistic", "variable"], - controlButtonCovered: true, - default: dstr, - controlButtonVisibility: "block", - displayOrder: 1, - displayPriority: 1, - displayGroup: 1, - help: "dateHelp.html", - }); - - const plotFormats = {}; - plotFormats[matsTypes.PlotFormats.matching] = "show matching diffs"; - plotFormats[matsTypes.PlotFormats.pairwise] = "pairwise diffs"; - plotFormats[matsTypes.PlotFormats.none] = "no diffs"; - matsCollections.PlotParams.insert({ - name: "plotFormat", - type: matsTypes.InputTypes.radioGroup, - optionsMap: plotFormats, - options: [ - matsTypes.PlotFormats.matching, - matsTypes.PlotFormats.pairwise, - matsTypes.PlotFormats.none, - ], - default: matsTypes.PlotFormats.none, - controlButtonCovered: false, - controlButtonVisibility: "block", - displayOrder: 1, - displayPriority: 1, - displayGroup: 3, - }); - - const yAxisOptionsMap = { - "Relative frequency": ["relFreq"], - Number: ["number"], - }; - matsCollections.PlotParams.insert({ - name: "histogram-yaxis-controls", - type: matsTypes.InputTypes.select, - optionsMap: yAxisOptionsMap, - options: Object.keys(yAxisOptionsMap), - default: Object.keys(yAxisOptionsMap)[0], - controlButtonCovered: true, - controlButtonText: "Y-axis mode", - displayOrder: 2, - displayPriority: 1, - displayGroup: 2, - }); - - const binOptionsMap = { - "Default bins": ["default"], - "Set number of bins": ["binNumber"], - "Make zero a bin bound": ["zeroBound"], - "Choose a bin bound": ["chooseBound"], - "Set number of bins and make zero a bin bound": ["binNumberWithZero"], - "Set number of bins and choose a bin bound": ["binNumberWithChosen"], - "Manual bins": ["manual"], - "Manual bin start, number, and stride": ["manualStride"], - }; - matsCollections.PlotParams.insert({ - name: "histogram-bin-controls", - type: matsTypes.InputTypes.select, - optionsMap: binOptionsMap, - options: Object.keys(binOptionsMap), - hideOtherFor: { - "bin-number": [ - "Default bins", - "Make zero a bin bound", - "Manual bins", - "Choose a bin bound", - ], - "bin-pivot": [ - "Default bins", - "Set number of bins", - "Make zero a bin bound", - "Set number of bins and make zero a bin bound", - "Manual bins", - "Manual bin start, number, and stride", - ], - "bin-start": [ - "Default bins", - "Set number of bins", - "Make zero a bin bound", - "Choose a bin bound", - "Set number of bins and make zero a bin bound", - "Set number of bins and choose a bin bound", - "Manual bins", - ], - "bin-stride": [ - "Default bins", - "Set number of bins", - "Make zero a bin bound", - "Choose a bin bound", - "Set number of bins and make zero a bin bound", - "Set number of bins and choose a bin bound", - "Manual bins", - ], - "bin-bounds": [ - "Default bins", - "Set number of bins", - "Make zero a bin bound", - "Choose a bin bound", - "Set number of bins and make zero a bin bound", - "Set number of bins and choose a bin bound", - "Manual bin start, number, and stride", - ], - }, - default: Object.keys(binOptionsMap)[0], - controlButtonCovered: true, - controlButtonText: "customize bins", - displayOrder: 3, - displayPriority: 1, - displayGroup: 2, - }); - - matsCollections.PlotParams.insert({ - name: "bin-number", - type: matsTypes.InputTypes.numberSpinner, - optionsMap: {}, - options: [], - min: "2", - max: "100", - step: "any", - default: "12", - controlButtonCovered: true, - controlButtonText: "number of bins", - displayOrder: 4, - displayPriority: 1, - displayGroup: 2, - }); - - matsCollections.PlotParams.insert({ - name: "bin-pivot", - type: matsTypes.InputTypes.numberSpinner, - optionsMap: {}, - options: [], - min: "-10000", - max: "10000", - step: "any", - default: "0", - controlButtonCovered: true, - controlButtonText: "bin pivot value", - displayOrder: 5, - displayPriority: 1, - displayGroup: 2, - }); - - matsCollections.PlotParams.insert({ - name: "bin-start", - type: matsTypes.InputTypes.numberSpinner, - optionsMap: {}, - options: [], - min: "-10000", - max: "10000", - step: "any", - default: "0", - controlButtonCovered: true, - controlButtonText: "bin start", - displayOrder: 6, - displayPriority: 1, - displayGroup: 2, - }); - - matsCollections.PlotParams.insert({ - name: "bin-stride", - type: matsTypes.InputTypes.numberSpinner, - optionsMap: {}, - options: [], - min: "-10000", - max: "10000", - step: "any", - default: "0", - controlButtonCovered: true, - controlButtonText: "bin stride", - displayOrder: 7, - displayPriority: 1, - displayGroup: 2, - }); - - matsCollections.PlotParams.insert({ - name: "bin-bounds", - type: matsTypes.InputTypes.textInput, - optionsMap: {}, - options: [], - default: " ", - controlButtonCovered: true, - controlButtonText: "bin bounds (Enter numbers separated by commas)", - displayOrder: 8, - displayPriority: 1, - displayGroup: 2, - }); - - const xOptionsMap = { - "Fcst lead time": "select ld.fcst_lead as xVal, ", - Threshold: "select h.fcst_thresh as xVal, ", - "Valid UTC hour": - "select unix_timestamp(ld.fcst_valid_beg)%(24*3600)/3600 as xVal, ", - "Init UTC hour": - "select unix_timestamp(ld.fcst_init_beg)%(24*3600)/3600 as xVal, ", - "Valid Date": "select unix_timestamp(ld.fcst_valid_beg) as xVal, ", - "Init Date": "select unix_timestamp(ld.fcst_init_beg) as xVal, ", - }; - - matsCollections.PlotParams.insert({ - name: "x-axis-parameter", - type: matsTypes.InputTypes.select, - options: Object.keys(xOptionsMap), - optionsMap: xOptionsMap, - selected: "", - controlButtonCovered: true, - unique: false, - default: Object.keys(xOptionsMap)[4], - controlButtonVisibility: "block", - displayOrder: 9, - displayPriority: 1, - displayGroup: 2, - }); - - const yOptionsMap = { - "Fcst lead time": "ld.fcst_lead as yVal, ", - Threshold: "h.fcst_thresh as yVal, ", - "Valid UTC hour": "unix_timestamp(ld.fcst_valid_beg)%(24*3600)/3600 as yVal, ", - "Init UTC hour": "unix_timestamp(ld.fcst_init_beg)%(24*3600)/3600 as yVal, ", - "Valid Date": "unix_timestamp(ld.fcst_valid_beg) as yVal, ", - "Init Date": "unix_timestamp(ld.fcst_init_beg) as yVal, ", - }; - - matsCollections.PlotParams.insert({ - name: "y-axis-parameter", - type: matsTypes.InputTypes.select, - options: Object.keys(yOptionsMap), - optionsMap: yOptionsMap, - selected: "", - controlButtonCovered: true, - unique: false, - default: Object.keys(yOptionsMap)[0], - controlButtonVisibility: "block", - displayOrder: 10, - displayPriority: 1, - displayGroup: 2, - }); - } else { - // need to update the dates selector if the metadata has changed - const currentParam = matsCollections.PlotParams.findOne({ name: "dates" }); - if ( - !matsDataUtils.areObjectsEqual(currentParam.startDate, minDate) || - !matsDataUtils.areObjectsEqual(currentParam.stopDate, maxDate) || - !matsDataUtils.areObjectsEqual(currentParam.default, dstr) - ) { - // have to reload model data - matsCollections.PlotParams.update( - { name: "dates" }, - { - $set: { - startDate: minDate, - stopDate: maxDate, - default: dstr, - }, - } - ); - } - } -}; - -const doCurveParams = function () { - // force a reset if requested - simply remove all the existing params to force a reload - if ( - matsCollections.Settings.findOne({}) === undefined || - matsCollections.Settings.findOne({}).resetFromCode === undefined || - matsCollections.Settings.findOne({}).resetFromCode === true - ) { - const params = matsCollections.CurveParamsInfo.find({ - curve_params: { $exists: true }, - }).fetch()[0].curve_params; - for (let cp = 0; cp < params.length; cp += 1) { - matsCollections[params[cp]].remove({}); - } - } - - const masterPlotTypeOptionsMap = { - line_data_sl1l2: [ - matsTypes.PlotTypes.timeSeries, - matsTypes.PlotTypes.dieoff, - matsTypes.PlotTypes.threshold, - matsTypes.PlotTypes.validtime, - matsTypes.PlotTypes.histogram, - matsTypes.PlotTypes.contour, - matsTypes.PlotTypes.simpleScatter, - ], - line_data_ctc: [ - matsTypes.PlotTypes.timeSeries, - matsTypes.PlotTypes.dieoff, - matsTypes.PlotTypes.threshold, - matsTypes.PlotTypes.validtime, - matsTypes.PlotTypes.histogram, - matsTypes.PlotTypes.contour, - ], - }; - - const masterStatsOptionsMap = { - line_data_sl1l2: { - RMSE: ["scalar"], - "Bias-corrected RMSE": ["scalar"], - MSE: ["scalar"], - "Bias-corrected MSE": ["scalar"], - "ME (Additive bias)": ["scalar"], - "Fractional Error": ["scalar"], - "Multiplicative bias": ["scalar"], - "Forecast mean": ["scalar"], - "Observed mean": ["scalar"], - "Forecast stdev": ["scalar"], - "Observed stdev": ["scalar"], - "Error stdev": ["scalar"], - "Pearson correlation": ["scalar"], - }, - line_data_ctc: { - "CSI (Critical Success Index)": ["ctc"], - "FAR (False Alarm Ratio)": ["ctc"], - "FBIAS (Frequency Bias)": ["ctc"], - "GSS (Gilbert Skill Score)": ["ctc"], - "HSS (Heidke Skill Score)": ["ctc"], - "PODy (Probability of positive detection)": ["ctc"], - "PODn (Probability of negative detection)": ["ctc"], - "POFD (Probability of false detection)": ["ctc"], - }, - }; - - const aggMethodOptionsMap = { - scalar: { - "Overall statistic": ["aggStat"], - "Mean statistic": ["meanStat"], - "Median statistic": ["medStat"], - }, - ctc: { - "Overall statistic": ["aggStat"], - "Mean statistic": ["meanStat"], - "Median statistic": ["medStat"], - }, - }; - - let masterStatsValuesMap = {}; - const lineTypes = Object.keys(masterStatsOptionsMap); - for (let si = 0; si < lineTypes.length; si += 1) { - masterStatsValuesMap = { - ...masterStatsValuesMap, - ...masterStatsOptionsMap[lineTypes[si]], - }; - } - - const myDBs = []; - const dbGroupMap = {}; - const modelOptionsMap = {}; - const dbDateRangeMap = {}; - const plotTypeOptionsMap = {}; - const statisticOptionsMap = {}; - const variableOptionsMap = {}; - const variableValuesMap = {}; - const regionModelOptionsMap = {}; - const forecastLengthOptionsMap = {}; - const levelOptionsMap = {}; - const thresholdOptionsMap = {}; - const imOptionsMap = {}; - const scaleOptionsMap = {}; - const descrOptionsMap = {}; - - let rows; - let thisGroup; - let dbs; - let dbArr; - try { - rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, - "select * from airquality_database_groups order by db_group;" - ); - for (let i = 0; i < rows.length; i += 1) { - thisGroup = rows[i].db_group.trim(); - dbs = rows[i].dbs; - dbArr = dbs.split(",").map(Function.prototype.call, String.prototype.trim); - for (let j = 0; j < dbArr.length; j += 1) { - dbArr[j] = dbArr[j].replace(/'|\[|\]/g, ""); - } - dbGroupMap[thisGroup] = dbArr; - } - } catch (err) { - throw new Error(err.message); - } - - let thisDB; - try { - rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, - "select distinct db from airquality_metexpress_metadata;" - ); - for (let i = 0; i < rows.length; i += 1) { - thisDB = rows[i].db.trim(); - myDBs.push(thisDB); - } - } catch (err) { - throw new Error(err.message); - } - - try { - for (let k = 0; k < myDBs.length; k += 1) { - thisDB = myDBs[k]; - modelOptionsMap[thisDB] = {}; - dbDateRangeMap[thisDB] = {}; - plotTypeOptionsMap[thisDB] = {}; - statisticOptionsMap[thisDB] = {}; - variableOptionsMap[thisDB] = {}; - variableValuesMap[thisDB] = {}; - regionModelOptionsMap[thisDB] = {}; - forecastLengthOptionsMap[thisDB] = {}; - levelOptionsMap[thisDB] = {}; - thresholdOptionsMap[thisDB] = {}; - imOptionsMap[thisDB] = {}; - scaleOptionsMap[thisDB] = {}; - descrOptionsMap[thisDB] = {}; - - rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, - `select model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,trshs,interp_mthds,gridpoints,mindate,maxdate from airquality_metexpress_metadata where db = '${thisDB}' group by model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,trshs,interp_mthds,gridpoints,mindate,maxdate order by model,line_data_table,variable;` - ); - for (let i = 0; i < rows.length; i += 1) { - const modelValue = rows[i].model.trim(); - const model = rows[i].display_text.trim(); - modelOptionsMap[thisDB][model] = [modelValue]; - - const rowMinDate = moment - .utc(rows[i].mindate * 1000) - .format("MM/DD/YYYY HH:mm"); - const rowMaxDate = moment - .utc(rows[i].maxdate * 1000) - .format("MM/DD/YYYY HH:mm"); - - const lineDataTable = rows[i].line_data_table.trim(); - const validPlotTypes = masterPlotTypeOptionsMap[lineDataTable]; - plotTypeOptionsMap[thisDB][model] = - plotTypeOptionsMap[thisDB][model] === undefined - ? validPlotTypes - : _.union(plotTypeOptionsMap[thisDB][model], validPlotTypes); - const validStats = masterStatsOptionsMap[lineDataTable]; - const variable = rows[i].variable.trim(); - - const { regions } = rows[i]; - const regionsArr = regions - .split(",") - .map(Function.prototype.call, String.prototype.trim); - for (let j = 0; j < regionsArr.length; j += 1) { - regionsArr[j] = regionsArr[j].replace(/'|\[|\]/g, ""); - } - - const forecastLengths = rows[i].fcst_orig; - const forecastLengthArr = forecastLengths - .split(",") - .map(Function.prototype.call, String.prototype.trim); - for (let j = 0; j < forecastLengthArr.length; j += 1) { - forecastLengthArr[j] = forecastLengthArr[j].replace(/'|\[|\]|0000/g, ""); - } - - const { levels } = rows[i]; - const levelsArrRaw = levels - .split(",") - .map(Function.prototype.call, String.prototype.trim); - const levelsArr = []; - let dummyLevel; - for (let j = 0; j < levelsArrRaw.length; j += 1) { - // sometimes bad vsdb parsing sticks an = on the end of levels in the db, so check for that. - dummyLevel = levelsArrRaw[j].replace(/'|\[|\]|=/g, ""); - if (levelsArr.indexOf(dummyLevel) === -1) { - levelsArr.push(dummyLevel); - } - } - - const { trshs } = rows[i]; - const trshArr = trshs - .split(",") - .map(Function.prototype.call, String.prototype.trim); - for (let j = 0; j < trshArr.length; j += 1) { - trshArr[j] = trshArr[j].replace(/'|\[|\]/g, ""); - } - trshArr.unshift("All thresholds"); - - const ims = rows[i].interp_mthds; - const imsArr = ims - .split(",") - .map(Function.prototype.call, String.prototype.trim); - for (let j = 0; j < imsArr.length; j += 1) { - imsArr[j] = imsArr[j].replace(/'|\[|\]/g, ""); - } - imsArr.unshift("All methods"); - - const scales = rows[i].gridpoints; - const scalesArr = scales - .split(",") - .map(Function.prototype.call, String.prototype.trim); - for (let j = 0; j < scalesArr.length; j += 1) { - scalesArr[j] = scalesArr[j].replace(/'|\[|\]/g, ""); - } - scalesArr.unshift("All scales"); - - const { descrs } = rows[i]; - const descrsArr = descrs - .split(",") - .map(Function.prototype.call, String.prototype.trim); - for (let j = 0; j < descrsArr.length; j += 1) { - descrsArr[j] = descrsArr[j].replace(/'|\[|\]|=/g, ""); - } - - statisticOptionsMap[thisDB][model] = - statisticOptionsMap[thisDB][model] === undefined - ? {} - : statisticOptionsMap[thisDB][model]; - variableOptionsMap[thisDB][model] = - variableOptionsMap[thisDB][model] === undefined - ? {} - : variableOptionsMap[thisDB][model]; - variableValuesMap[thisDB][model] = - variableValuesMap[thisDB][model] === undefined - ? {} - : variableValuesMap[thisDB][model]; - regionModelOptionsMap[thisDB][model] = - regionModelOptionsMap[thisDB][model] === undefined - ? {} - : regionModelOptionsMap[thisDB][model]; - forecastLengthOptionsMap[thisDB][model] = - forecastLengthOptionsMap[thisDB][model] === undefined - ? {} - : forecastLengthOptionsMap[thisDB][model]; - levelOptionsMap[thisDB][model] = - levelOptionsMap[thisDB][model] === undefined - ? {} - : levelOptionsMap[thisDB][model]; - thresholdOptionsMap[thisDB][model] = - thresholdOptionsMap[thisDB][model] === undefined - ? {} - : thresholdOptionsMap[thisDB][model]; - imOptionsMap[thisDB][model] = - imOptionsMap[thisDB][model] === undefined ? {} : imOptionsMap[thisDB][model]; - scaleOptionsMap[thisDB][model] = - scaleOptionsMap[thisDB][model] === undefined - ? {} - : scaleOptionsMap[thisDB][model]; - descrOptionsMap[thisDB][model] = - descrOptionsMap[thisDB][model] === undefined - ? {} - : descrOptionsMap[thisDB][model]; - dbDateRangeMap[thisDB][model] = - dbDateRangeMap[thisDB][model] === undefined - ? {} - : dbDateRangeMap[thisDB][model]; - - let thisPlotType; - for (let ptidx = 0; ptidx < validPlotTypes.length; ptidx += 1) { - thisPlotType = validPlotTypes[ptidx]; - if (statisticOptionsMap[thisDB][model][thisPlotType] === undefined) { - // if we haven't encountered this plot type for this model yet, initialize everything - statisticOptionsMap[thisDB][model][thisPlotType] = validStats; - variableOptionsMap[thisDB][model][thisPlotType] = {}; - variableValuesMap[thisDB][model][thisPlotType] = {}; - regionModelOptionsMap[thisDB][model][thisPlotType] = {}; - forecastLengthOptionsMap[thisDB][model][thisPlotType] = {}; - levelOptionsMap[thisDB][model][thisPlotType] = {}; - thresholdOptionsMap[thisDB][model][thisPlotType] = {}; - imOptionsMap[thisDB][model][thisPlotType] = {}; - scaleOptionsMap[thisDB][model][thisPlotType] = {}; - descrOptionsMap[thisDB][model][thisPlotType] = {}; - dbDateRangeMap[thisDB][model][thisPlotType] = {}; - } else { - // if we have encountered this plot type for this model, add in any new stats - statisticOptionsMap[thisDB][model][thisPlotType] = { - ...statisticOptionsMap[thisDB][model][thisPlotType], - ...validStats, - }; - } - const jsonFriendlyVariable = variable.replace(/\./g, "_"); - const theseValidStats = Object.keys(validStats); - let thisValidStatType; - for (let vsidx = 0; vsidx < theseValidStats.length; vsidx += 1) { - [thisValidStatType] = validStats[theseValidStats[vsidx]]; - if ( - variableValuesMap[thisDB][model][thisPlotType][thisValidStatType] === - undefined - ) { - // if we haven't encountered this variable for this stat yet, initialize everything - variableOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = []; - variableValuesMap[thisDB][model][thisPlotType][thisValidStatType] = {}; - regionModelOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = - {}; - forecastLengthOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = - {}; - levelOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = {}; - thresholdOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = {}; - imOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = {}; - scaleOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = {}; - descrOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = {}; - dbDateRangeMap[thisDB][model][thisPlotType][thisValidStatType] = {}; - } - if ( - variableValuesMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] === undefined - ) { - // if we haven't encountered this variable for this plot type yet, just store the variable-dependent arrays - variableOptionsMap[thisDB][model][thisPlotType][thisValidStatType].push( - jsonFriendlyVariable - ); - variableValuesMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = variable; - regionModelOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = regionsArr; - forecastLengthOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = forecastLengthArr; - levelOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = levelsArr; - thresholdOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = trshArr; - imOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = imsArr; - scaleOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = scalesArr; - descrOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = descrsArr; - dbDateRangeMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = { minDate: rowMinDate, maxDate: rowMaxDate }; - } else { - // if we have encountered this variable for this plot type, we need to take the unions of existing and new arrays - regionModelOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = _.union( - regionModelOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ], - regionsArr - ); - forecastLengthOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = _.union( - forecastLengthOptionsMap[thisDB][model][thisPlotType][ - thisValidStatType - ][jsonFriendlyVariable], - forecastLengthArr - ); - levelOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = _.union( - levelOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ], - levelsArr - ); - thresholdOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = _.union( - thresholdOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ], - trshArr - ); - imOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = _.union( - imOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ], - imsArr - ); - scaleOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = _.union( - scaleOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ], - scalesArr - ); - descrOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ] = _.union( - descrOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ], - descrsArr - ); - dbDateRangeMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ].minDate = - dbDateRangeMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ].minDate < rowMinDate - ? dbDateRangeMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ].minDate - : rowMinDate; - dbDateRangeMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ].maxDate = - dbDateRangeMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ].maxDate > rowMaxDate - ? dbDateRangeMap[thisDB][model][thisPlotType][thisValidStatType][ - jsonFriendlyVariable - ].maxDate - : rowMaxDate; - } - } - } - } - } - } catch (err) { - throw new Error(err.message); - } - - if (matsCollections.label.findOne({ name: "label" }) === undefined) { - matsCollections.label.insert({ - name: "label", - type: matsTypes.InputTypes.textInput, - optionsMap: {}, - options: [], - controlButtonCovered: true, - default: "", - unique: true, - controlButtonVisibility: "block", - displayOrder: 1, - displayPriority: 1, - displayGroup: 1, - help: "label.html", - }); - } - // get the default group, db, and model that were specified in the settings file. If none exist, take - // the first available option for each in the selector. - const requestedGroup = matsCollections.Settings.findOne({}).appDefaultGroup; - const defaultGroup = - Object.keys(dbGroupMap).indexOf(requestedGroup) !== -1 - ? requestedGroup - : Object.keys(dbGroupMap)[0]; - const requestedDB = matsCollections.Settings.findOne({}).appDefaultDB; - const defaultDB = - dbGroupMap[defaultGroup].indexOf(requestedDB) !== -1 - ? requestedDB - : dbGroupMap[defaultGroup][0]; - const requestedModel = matsCollections.Settings.findOne({}).appDefaultModel; - const defaultModel = - Object.keys(modelOptionsMap[defaultDB]).indexOf(requestedModel) !== -1 - ? requestedModel - : Object.keys(modelOptionsMap[defaultDB])[0]; - - // these defaults are app-specific and not controlled by the user - const defaultPlotType = matsTypes.PlotTypes.timeSeries; - const defaultStatistic = Object.keys( - statisticOptionsMap[defaultDB][defaultModel][defaultPlotType] - )[0]; - const defaultStatType = masterStatsValuesMap[defaultStatistic][0]; - - if (matsCollections.group.findOne({ name: "group" }) === undefined) { - matsCollections.group.insert({ - name: "group", - type: matsTypes.InputTypes.select, - options: Object.keys(dbGroupMap), - dependentNames: ["database"], - controlButtonCovered: true, - default: defaultGroup, - unique: false, - controlButtonVisibility: "block", - displayOrder: 1, - displayPriority: 1, - displayGroup: 2, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections.group.findOne({ name: "group" }); - if (!matsDataUtils.areObjectsEqual(currentParam.options, Object.keys(dbGroupMap))) { - // have to reload group data - matsCollections.group.update( - { name: "group" }, - { - $set: { - options: Object.keys(dbGroupMap), - default: defaultGroup, - }, - } - ); - } - } - - if (matsCollections.database.findOne({ name: "database" }) === undefined) { - matsCollections.database.insert({ - name: "database", - type: matsTypes.InputTypes.select, - optionsMap: dbGroupMap, - options: dbGroupMap[defaultGroup], - dates: dbDateRangeMap, - superiorNames: ["group"], - dependentNames: ["data-source"], - controlButtonCovered: true, - default: defaultDB, - unique: false, - controlButtonVisibility: "block", - displayOrder: 2, - displayPriority: 1, - displayGroup: 2, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections.database.findOne({ name: "database" }); - if ( - !matsDataUtils.areObjectsEqual(currentParam.optionsMap, dbGroupMap) || - !matsDataUtils.areObjectsEqual(currentParam.dates, dbDateRangeMap) - ) { - // have to reload database data - matsCollections.database.update( - { name: "database" }, - { - $set: { - optionsMap: dbGroupMap, - dates: dbDateRangeMap, - options: dbGroupMap[defaultGroup], - default: defaultDB, - }, - } - ); - } - } - - if (matsCollections["data-source"].findOne({ name: "data-source" }) === undefined) { - matsCollections["data-source"].insert({ - name: "data-source", - type: matsTypes.InputTypes.select, - optionsMap: modelOptionsMap, - options: Object.keys(modelOptionsMap[defaultDB]), - superiorNames: ["database"], - dependentNames: ["plot-type"], - controlButtonCovered: true, - default: defaultModel, - unique: false, - controlButtonVisibility: "block", - displayOrder: 3, - displayPriority: 1, - displayGroup: 2, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections["data-source"].findOne({ - name: "data-source", - }); - if (!matsDataUtils.areObjectsEqual(modelOptionsMap, currentParam.optionsMap)) { - // have to reload model data - matsCollections["data-source"].update( - { name: "data-source" }, - { - $set: { - optionsMap: modelOptionsMap, - options: Object.keys(modelOptionsMap[defaultDB]), - default: defaultModel, - }, - } - ); - } - } - - if (matsCollections["plot-type"].findOne({ name: "plot-type" }) === undefined) { - matsCollections["plot-type"].insert({ - name: "plot-type", - type: matsTypes.InputTypes.select, - optionsMap: plotTypeOptionsMap, - options: plotTypeOptionsMap[defaultDB][defaultModel], - superiorNames: ["database", "data-source"], - dependentNames: ["statistic", "y-statistic"], - controlButtonCovered: false, - default: defaultPlotType, - unique: false, - controlButtonVisibility: "none", - displayOrder: 4, - displayPriority: 1, - displayGroup: 2, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections["plot-type"].findOne({ name: "plot-type" }); - if (!matsDataUtils.areObjectsEqual(plotTypeOptionsMap, currentParam.optionsMap)) { - // have to reload model data - matsCollections["plot-type"].update( - { name: "plot-type" }, - { - $set: { - optionsMap: plotTypeOptionsMap, - options: plotTypeOptionsMap[defaultDB][defaultModel], - default: defaultPlotType, - }, - } - ); - } - } - - // these defaults are app-specific and not controlled by the user - const regionOptions = - regionModelOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - regionModelOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType] - )[0] - ]; - let regionDefault; - if (regionOptions.indexOf("FULL") !== -1) { - regionDefault = "FULL"; - } else if (regionOptions.indexOf("G002") !== -1) { - regionDefault = "G002"; - } else if (regionOptions.indexOf("CONUS") !== -1) { - regionDefault = "CONUS"; - } else { - [regionDefault] = regionOptions; - } - - if (matsCollections.region.findOne({ name: "region" }) === undefined) { - matsCollections.region.insert({ - name: "region", - type: matsTypes.InputTypes.select, - optionsMap: regionModelOptionsMap, - options: regionOptions, - superiorNames: ["database", "data-source", "plot-type", "statistic", "variable"], - controlButtonCovered: true, - unique: false, - default: regionDefault, - controlButtonVisibility: "block", - displayOrder: 1, - displayPriority: 1, - displayGroup: 3, - help: "region.html", - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections.region.findOne({ name: "region" }); - if ( - !matsDataUtils.areObjectsEqual(regionModelOptionsMap, currentParam.optionsMap) - ) { - // have to reload region data - matsCollections.region.update( - { name: "region" }, - { - $set: { - optionsMap: regionModelOptionsMap, - options: regionOptions, - default: regionDefault, - }, - } - ); - } - } - - if (matsCollections.statistic.findOne({ name: "statistic" }) === undefined) { - matsCollections.statistic.insert({ - name: "statistic", - type: matsTypes.InputTypes.select, - optionsMap: statisticOptionsMap, - options: Object.keys( - statisticOptionsMap[defaultDB][defaultModel][defaultPlotType] - ), - valuesMap: masterStatsValuesMap, - superiorNames: ["database", "data-source", "plot-type"], - dependentNames: ["variable", "aggregation-method"], - controlButtonCovered: true, - unique: false, - default: defaultStatistic, - controlButtonText: "statistic", - controlButtonVisibility: "block", - displayOrder: 2, - displayPriority: 1, - displayGroup: 3, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections.statistic.findOne({ name: "statistic" }); - if (!matsDataUtils.areObjectsEqual(statisticOptionsMap, currentParam.optionsMap)) { - // have to reload region data - matsCollections.statistic.update( - { name: "statistic" }, - { - $set: { - optionsMap: statisticOptionsMap, - options: Object.keys( - statisticOptionsMap[defaultDB][defaultModel][defaultPlotType] - ), - default: defaultStatistic, - }, - } - ); - } - } - - if (matsCollections["y-statistic"].findOne({ name: "y-statistic" }) === undefined) { - matsCollections["y-statistic"].insert({ - name: "y-statistic", - type: matsTypes.InputTypes.select, - optionsMap: statisticOptionsMap, - options: Object.keys( - statisticOptionsMap[defaultDB][defaultModel][defaultPlotType] - ), - valuesMap: masterStatsValuesMap, - superiorNames: ["database", "data-source", "plot-type"], - dependentNames: ["y-variable"], - controlButtonCovered: true, - unique: false, - default: defaultStatistic, - controlButtonVisibility: "block", - displayOrder: 4, - displayPriority: 1, - displayGroup: 3, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections["y-statistic"].findOne({ - name: "y-statistic", - }); - if (!matsDataUtils.areObjectsEqual(statisticOptionsMap, currentParam.optionsMap)) { - // have to reload region data - matsCollections["y-statistic"].update( - { name: "y-statistic" }, - { - $set: { - optionsMap: statisticOptionsMap, - options: Object.keys( - statisticOptionsMap[defaultDB][defaultModel][defaultPlotType] - ), - default: defaultStatistic, - }, - } - ); - } - } - - if (matsCollections.variable.findOne({ name: "variable" }) === undefined) { - matsCollections.variable.insert({ - name: "variable", - type: matsTypes.InputTypes.select, - optionsMap: variableOptionsMap, - options: - variableOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType], - valuesMap: variableValuesMap, - superiorNames: ["database", "data-source", "plot-type", "statistic"], - dependentNames: [ - "region", - "forecast-length", - "level", - "threshold", - "interp-method", - "scale", - "description", - "dates", - "curve-dates", - ], - controlButtonCovered: true, - unique: false, - default: - variableOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ][0], - controlButtonText: "variable", - controlButtonVisibility: "block", - gapBelow: true, - displayOrder: 3, - displayPriority: 1, - displayGroup: 3, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections.variable.findOne({ name: "variable" }); - if ( - !matsDataUtils.areObjectsEqual(variableOptionsMap, currentParam.optionsMap) || - !matsDataUtils.areObjectsEqual(variableValuesMap, currentParam.valuesMap) - ) { - // have to reload variable data - matsCollections.variable.update( - { name: "variable" }, - { - $set: { - optionsMap: variableOptionsMap, - valuesMap: variableValuesMap, - options: - variableOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ], - default: - variableOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ][0], - }, - } - ); - } - } - - if (matsCollections["y-variable"].findOne({ name: "y-variable" }) === undefined) { - matsCollections["y-variable"].insert({ - name: "y-variable", - type: matsTypes.InputTypes.select, - optionsMap: variableOptionsMap, - options: - variableOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType], - valuesMap: variableValuesMap, - superiorNames: ["database", "data-source", "plot-type", "y-statistic"], - controlButtonCovered: true, - unique: false, - default: - variableOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ][0], - controlButtonVisibility: "block", - gapBelow: true, - displayOrder: 5, - displayPriority: 1, - displayGroup: 3, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections["y-variable"].findOne({ name: "y-variable" }); - if ( - !matsDataUtils.areObjectsEqual(variableOptionsMap, currentParam.optionsMap) || - !matsDataUtils.areObjectsEqual(variableValuesMap, currentParam.valuesMap) - ) { - // have to reload variable data - matsCollections["y-variable"].update( - { name: "y-variable" }, - { - $set: { - optionsMap: variableOptionsMap, - valuesMap: variableValuesMap, - options: - variableOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ], - default: - variableOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ][0], - }, - } - ); - } - } - - if (matsCollections.threshold.findOne({ name: "threshold" }) === undefined) { - matsCollections.threshold.insert({ - name: "threshold", - type: matsTypes.InputTypes.select, - optionsMap: thresholdOptionsMap, - options: - thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ] - )[0] - ], - superiorNames: ["database", "data-source", "plot-type", "statistic", "variable"], - controlButtonCovered: true, - unique: false, - default: - thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ] - )[0] - ][0], - controlButtonVisibility: "block", - displayOrder: 1, - displayPriority: 1, - displayGroup: 4, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections.threshold.findOne({ name: "threshold" }); - if (!matsDataUtils.areObjectsEqual(thresholdOptionsMap, currentParam.optionsMap)) { - // have to reload threshold data - matsCollections.threshold.update( - { name: "threshold" }, - { - $set: { - optionsMap: thresholdOptionsMap, - options: - thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ][ - Object.keys( - thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ] - )[0] - ], - default: - thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ][ - Object.keys( - thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ] - )[0] - ][0], - }, - } - ); - } - } - - if ( - matsCollections["interp-method"].findOne({ name: "interp-method" }) === undefined - ) { - matsCollections["interp-method"].insert({ - name: "interp-method", - type: matsTypes.InputTypes.select, - optionsMap: imOptionsMap, - options: - imOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - imOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType] - )[0] - ], - superiorNames: ["database", "data-source", "plot-type", "statistic", "variable"], - controlButtonCovered: true, - unique: false, - default: - imOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - imOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType] - )[0] - ][0], - controlButtonVisibility: "block", - controlButtonText: "interpolation method", - gapAbove: true, - displayOrder: 2, - displayPriority: 1, - displayGroup: 4, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections["interp-method"].findOne({ - name: "interp-method", - }); - if (!matsDataUtils.areObjectsEqual(imOptionsMap, currentParam.optionsMap)) { - // have to reload im data - matsCollections["interp-method"].update( - { name: "interp-method" }, - { - $set: { - optionsMap: imOptionsMap, - options: - imOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - imOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ] - )[0] - ], - default: - imOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - imOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ] - )[0] - ][0], - }, - } - ); - } - } - - if (matsCollections.scale.findOne({ name: "scale" }) === undefined) { - matsCollections.scale.insert({ - name: "scale", - type: matsTypes.InputTypes.select, - optionsMap: scaleOptionsMap, - options: - scaleOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - scaleOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType] - )[0] - ], - superiorNames: ["database", "data-source", "plot-type", "statistic", "variable"], - controlButtonCovered: true, - unique: false, - default: - scaleOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - scaleOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType] - )[0] - ][0], - controlButtonVisibility: "block", - displayOrder: 3, - displayPriority: 1, - displayGroup: 4, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections.scale.findOne({ name: "scale" }); - if (!matsDataUtils.areObjectsEqual(scaleOptionsMap, currentParam.optionsMap)) { - // have to reload scale data - matsCollections.scale.update( - { name: "scale" }, - { - $set: { - optionsMap: scaleOptionsMap, - options: - scaleOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ][ - Object.keys( - scaleOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ] - )[0] - ], - default: - scaleOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ][ - Object.keys( - scaleOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ] - )[0] - ][0], - }, - } - ); - } - } - - // these defaults are app-specific and not controlled by the user - const fhrOptions = - forecastLengthOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - forecastLengthOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ] - )[0] - ]; - let fhrDefault; - if (fhrOptions.indexOf("24") !== -1) { - fhrDefault = "24"; - } else if (fhrOptions.indexOf("12") !== -1) { - fhrDefault = "12"; - } else { - [fhrDefault] = fhrOptions; - } - - if ( - matsCollections["forecast-length"].findOne({ name: "forecast-length" }) === - undefined - ) { - matsCollections["forecast-length"].insert({ - name: "forecast-length", - type: matsTypes.InputTypes.select, - optionsMap: forecastLengthOptionsMap, - options: fhrOptions, - superiorNames: ["database", "data-source", "plot-type", "statistic", "variable"], - selected: "", - controlButtonCovered: true, - unique: false, - default: fhrDefault, - controlButtonVisibility: "block", - controlButtonText: "forecast lead time", - displayOrder: 1, - displayPriority: 1, - displayGroup: 5, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections["forecast-length"].findOne({ - name: "forecast-length", - }); - if ( - !matsDataUtils.areObjectsEqual(currentParam.optionsMap, forecastLengthOptionsMap) - ) { - // have to reload forecast length data - matsCollections["forecast-length"].update( - { name: "forecast-length" }, - { - $set: { - optionsMap: forecastLengthOptionsMap, - options: fhrOptions, - default: fhrDefault, - }, - } - ); - } - } - - if (matsCollections["dieoff-type"].findOne({ name: "dieoff-type" }) === undefined) { - const dieoffOptionsMap = { - Dieoff: [matsTypes.ForecastTypes.dieoff], - "Dieoff for a specified UTC cycle init hour": [matsTypes.ForecastTypes.utcCycle], - "Single cycle forecast (uses first date in range)": [ - matsTypes.ForecastTypes.singleCycle, - ], - }; - matsCollections["dieoff-type"].insert({ - name: "dieoff-type", - type: matsTypes.InputTypes.select, - optionsMap: dieoffOptionsMap, - options: Object.keys(dieoffOptionsMap), - hideOtherFor: { - "valid-time": [ - "Dieoff for a specified UTC cycle init hour", - "Single cycle forecast (uses first date in range)", - ], - "utc-cycle-start": [ - "Dieoff", - "Single cycle forecast (uses first date in range)", - ], - }, - controlButtonCovered: true, - unique: false, - default: Object.keys(dieoffOptionsMap)[0], - controlButtonVisibility: "block", - controlButtonText: "dieoff type", - displayOrder: 2, - displayPriority: 1, - displayGroup: 5, - }); - } - - if (matsCollections["valid-time"].findOne({ name: "valid-time" }) === undefined) { - matsCollections["valid-time"].insert({ - name: "valid-time", - type: matsTypes.InputTypes.select, - options: [ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - "17", - "18", - "19", - "20", - "21", - "22", - "23", - ], - selected: [], - controlButtonCovered: true, - unique: false, - default: matsTypes.InputTypes.unused, - controlButtonVisibility: "block", - controlButtonText: "valid utc hour", - displayOrder: 3, - displayPriority: 1, - displayGroup: 5, - multiple: true, - }); - } - - if ( - matsCollections["utc-cycle-start"].findOne({ name: "utc-cycle-start" }) === - undefined - ) { - matsCollections["utc-cycle-start"].insert({ - name: "utc-cycle-start", - type: matsTypes.InputTypes.select, - options: [ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - "17", - "18", - "19", - "20", - "21", - "22", - "23", - ], - selected: "", - controlButtonCovered: true, - unique: false, - default: ["12"], - controlButtonVisibility: "block", - controlButtonText: "utc cycle init hour", - displayOrder: 4, - displayPriority: 1, - displayGroup: 5, - multiple: true, - }); - } - - if (matsCollections.average.findOne({ name: "average" }) === undefined) { - const optionsMap = { - None: ["unix_timestamp(ld.fcst_valid_beg)"], - "1hr": [ - `ceil(${3600}*floor(((unix_timestamp(ld.fcst_valid_beg))+${3600}/2)/${3600}))`, - ], - "3hr": [ - `ceil(${3600 * 3}*floor(((unix_timestamp(ld.fcst_valid_beg))+${3600 * 3}/2)/${ - 3600 * 3 - }))`, - ], - "6hr": [ - `ceil(${3600 * 6}*floor(((unix_timestamp(ld.fcst_valid_beg))+${3600 * 6}/2)/${ - 3600 * 6 - }))`, - ], - "12hr": [ - `ceil(${3600 * 12}*floor(((unix_timestamp(ld.fcst_valid_beg))+${3600 * 12}/2)/${ - 3600 * 12 - }))`, - ], - "1D": [ - `ceil(${3600 * 24}*floor(((unix_timestamp(ld.fcst_valid_beg))+${3600 * 24}/2)/${ - 3600 * 24 - }))`, - ], - "3D": [ - `ceil(${3600 * 24 * 3}*floor(((unix_timestamp(ld.fcst_valid_beg))+${ - 3600 * 24 * 3 - }/2)/${3600 * 24 * 3}))`, - ], - "7D": [ - `ceil(${3600 * 24 * 7}*floor(((unix_timestamp(ld.fcst_valid_beg))+${ - 3600 * 24 * 7 - }/2)/${3600 * 24 * 7}))`, - ], - "30D": [ - `ceil(${3600 * 24 * 30}*floor(((unix_timestamp(ld.fcst_valid_beg))+${ - 3600 * 24 * 30 - }/2)/${3600 * 24 * 30}))`, - ], - "60D": [ - `ceil(${3600 * 24 * 60}*floor(((unix_timestamp(ld.fcst_valid_beg))+${ - 3600 * 24 * 60 - }/2)/${3600 * 24 * 60}))`, - ], - "90D": [ - `ceil(${3600 * 24 * 90}*floor(((unix_timestamp(ld.fcst_valid_beg))+${ - 3600 * 24 * 90 - }/2)/${3600 * 24 * 90}))`, - ], - "180D": [ - `ceil(${3600 * 24 * 180}*floor(((unix_timestamp(ld.fcst_valid_beg))+${ - 3600 * 24 * 180 - }/2)/${3600 * 24 * 180}))`, - ], - }; - matsCollections.average.insert({ - name: "average", - type: matsTypes.InputTypes.select, - optionsMap, - options: Object.keys(optionsMap), - controlButtonCovered: true, - unique: false, - default: "None", - controlButtonVisibility: "block", - displayOrder: 1, - displayPriority: 1, - displayGroup: 6, - }); - } - - // these defaults are app-specific and not controlled by the user - const levelOptions = - levelOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - levelOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType] - )[0] - ]; - let levelDefault; - if (levelOptions.indexOf("SFC") !== -1) { - levelDefault = "SFC"; - } else if (levelOptions.indexOf("Z0") !== -1) { - levelDefault = "Z0"; - } else if (levelOptions.indexOf("L0") !== -1) { - levelDefault = "L0"; - } else { - [levelDefault] = levelOptions; - } - - if (matsCollections.level.findOne({ name: "level" }) === undefined) { - matsCollections.level.insert({ - name: "level", - type: matsTypes.InputTypes.select, - optionsMap: levelOptionsMap, - options: levelOptions, - superiorNames: ["database", "data-source", "plot-type", "statistic", "variable"], - selected: "", - controlButtonCovered: true, - unique: false, - default: levelDefault, - controlButtonVisibility: "block", - controlButtonText: "Ground Level", - displayOrder: 2, - displayPriority: 1, - displayGroup: 6, - multiple: false, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections.level.findOne({ name: "level" }); - if (!matsDataUtils.areObjectsEqual(levelOptionsMap, currentParam.optionsMap)) { - // have to reload level data - matsCollections.level.update( - { name: "level" }, - { - $set: { - optionsMap: levelOptionsMap, - options: levelOptions, - default: levelDefault, - }, - } - ); - } - } - - if (matsCollections.description.findOne({ name: "description" }) === undefined) { - matsCollections.description.insert({ - name: "description", - type: matsTypes.InputTypes.select, - optionsMap: descrOptionsMap, - options: - descrOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - descrOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType] - )[0] - ], - superiorNames: ["database", "data-source", "plot-type", "statistic", "variable"], - selected: "", - controlButtonCovered: true, - unique: false, - default: matsTypes.InputTypes.unused, - controlButtonVisibility: "block", - gapBelow: true, - displayOrder: 3, - displayPriority: 1, - displayGroup: 6, - multiple: true, - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections.description.findOne({ name: "description" }); - if (!matsDataUtils.areObjectsEqual(descrOptionsMap, currentParam.optionsMap)) { - // have to reload description data - matsCollections.description.update( - { name: "description" }, - { - $set: { - optionsMap: descrOptionsMap, - options: - descrOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ][ - Object.keys( - descrOptionsMap[defaultDB][defaultModel][defaultPlotType][ - defaultStatType - ] - )[0] - ], - default: matsTypes.InputTypes.unused, - }, - } - ); - } - } - - if ( - matsCollections["aggregation-method"].findOne({ name: "aggregation-method" }) === - undefined - ) { - matsCollections["aggregation-method"].insert({ - name: "aggregation-method", - type: matsTypes.InputTypes.select, - optionsMap: aggMethodOptionsMap, - options: Object.keys(aggMethodOptionsMap[defaultStatType]), - superiorNames: ["statistic"], - default: Object.keys(aggMethodOptionsMap[defaultStatType])[0], - controlButtonCovered: true, - gapAbove: true, - displayOrder: 1, - displayPriority: 1, - displayGroup: 7, - }); - } - - if ( - matsCollections["bin-parameter"].findOne({ name: "bin-parameter" }) === undefined - ) { - const optionsMap = { - "Fcst lead time": "select ld.fcst_lead as binVal, ", - "Valid UTC hour": - "select unix_timestamp(ld.fcst_valid_beg)%(24*3600)/3600 as binVal, ", - "Init UTC hour": - "select unix_timestamp(ld.fcst_init_beg)%(24*3600)/3600 as binVal, ", - "Valid Date": "select unix_timestamp(ld.fcst_valid_beg) as binVal, ", - "Init Date": "select unix_timestamp(ld.fcst_init_beg) as binVal, ", - }; - - matsCollections["bin-parameter"].insert({ - name: "bin-parameter", - type: matsTypes.InputTypes.select, - options: Object.keys(optionsMap), - optionsMap, - hideOtherFor: { - "forecast-length": ["Fcst lead time"], - "valid-time": ["Valid UTC hour"], - }, - selected: "", - controlButtonCovered: true, - unique: false, - default: Object.keys(optionsMap)[3], - controlButtonVisibility: "block", - displayOrder: 2, - displayPriority: 1, - displayGroup: 7, - }); - } - - // determine date defaults for dates and curveDates - // these defaults are app-specific and not controlled by the user - minDate = - dbDateRangeMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - regionModelOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType] - )[0] - ].minDate; - maxDate = - dbDateRangeMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ - Object.keys( - regionModelOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType] - )[0] - ].maxDate; - - // need to turn the raw max and min from the metadata into the last valid month of data - const newDateRange = matsParamUtils.getMinMaxDates(minDate, maxDate); - const minusMonthMinDate = newDateRange.minDate; - maxDate = newDateRange.maxDate; - dstr = `${moment.utc(minusMonthMinDate).format("MM/DD/YYYY HH:mm")} - ${moment - .utc(maxDate) - .format("MM/DD/YYYY HH:mm")}`; - - if (matsCollections["curve-dates"].findOne({ name: "curve-dates" }) === undefined) { - const optionsMap = { - "1 day": ["1 day"], - "3 days": ["3 days"], - "7 days": ["7 days"], - "31 days": ["31 days"], - "90 days": ["90 days"], - "180 days": ["180 days"], - "365 days": ["365 days"], - }; - matsCollections["curve-dates"].insert({ - name: "curve-dates", - type: matsTypes.InputTypes.dateRange, - optionsMap, - options: Object.keys(optionsMap).sort(), - startDate: minDate, - stopDate: maxDate, - superiorNames: ["database", "data-source", "plot-type", "statistic", "variable"], - controlButtonCovered: true, - unique: false, - default: dstr, - controlButtonVisibility: "block", - displayOrder: 1, - displayPriority: 1, - displayGroup: 8, - help: "dateHelp.html", - }); - } else { - // it is defined but check for necessary update - const currentParam = matsCollections["curve-dates"].findOne({ - name: "curve-dates", - }); - if ( - !matsDataUtils.areObjectsEqual(currentParam.startDate, minDate) || - !matsDataUtils.areObjectsEqual(currentParam.stopDate, maxDate) || - !matsDataUtils.areObjectsEqual(currentParam.default, dstr) - ) { - // have to reload dates data - matsCollections["curve-dates"].update( - { name: "curve-dates" }, - { - $set: { - startDate: minDate, - stopDate: maxDate, - default: dstr, - }, - } - ); - } - } -}; - -/* The format of a curveTextPattern is an array of arrays, each sub array has - [labelString, localVariableName, delimiterString] any of which can be null. - Each sub array will be joined (the localVariableName is always dereferenced first) - and then the sub arrays will be joined maintaining order. - - The curveTextPattern is found by its name which must match the corresponding matsCollections.PlotGraphFunctions.PlotType value. - See curve_item.js and standAlone.js. - */ -const doCurveTextPatterns = function () { - if ( - matsCollections.Settings.findOne({}) === undefined || - matsCollections.Settings.findOne({}).resetFromCode === undefined || - matsCollections.Settings.findOne({}).resetFromCode === true - ) { - matsCollections.CurveTextPatterns.remove({}); - } - if (matsCollections.CurveTextPatterns.find().count() === 0) { - matsCollections.CurveTextPatterns.insert({ - plotType: matsTypes.PlotTypes.timeSeries, - textPattern: [ - ["", "label", ": "], - ["", "database", "."], - ["", "data-source", " in "], - ["", "region", ", "], - ["", "threshold", ", "], - ["", "interp-method", " "], - ["", "scale", ", "], - ["", "variable", " "], - ["", "statistic", " "], - ["", "aggregation-method", ", "], - ["level: ", "level", ", "], - ["fcst_len: ", "forecast-length", "h, "], - ["valid-time: ", "valid-time", ", "], - ["avg: ", "average", ""], - [", desc: ", "description", ""], - ], - displayParams: [ - "label", - "group", - "database", - "data-source", - "region", - "statistic", - "variable", - "threshold", - "interp-method", - "scale", - "valid-time", - "average", - "forecast-length", - "level", - "description", - "aggregation-method", - ], - groupSize: 6, - }); - matsCollections.CurveTextPatterns.insert({ - plotType: matsTypes.PlotTypes.dieoff, - textPattern: [ - ["", "label", ": "], - ["", "database", "."], - ["", "data-source", " in "], - ["", "region", ", "], - ["", "threshold", ", "], - ["", "interp-method", " "], - ["", "scale", ", "], - ["", "variable", " "], - ["", "statistic", " "], - ["", "aggregation-method", ", "], - ["level: ", "level", ", "], - ["", "dieoff-type", ", "], - ["valid-time: ", "valid-time", ", "], - ["start utc: ", "utc-cycle-start", ", "], - ["desc: ", "description", ", "], - ["", "curve-dates", ""], - ], - displayParams: [ - "label", - "group", - "database", - "data-source", - "region", - "statistic", - "variable", - "threshold", - "interp-method", - "scale", - "dieoff-type", - "valid-time", - "utc-cycle-start", - "level", - "description", - "aggregation-method", - "curve-dates", - ], - groupSize: 6, - }); - matsCollections.CurveTextPatterns.insert({ - plotType: matsTypes.PlotTypes.threshold, - textPattern: [ - ["", "label", ": "], - ["", "database", "."], - ["", "data-source", " in "], - ["", "region", ", "], - ["", "interp-method", " "], - ["", "scale", ", "], - ["", "variable", " "], - ["", "statistic", " "], - ["", "aggregation-method", ", "], - ["level: ", "level", ", "], - ["fcst_len: ", "forecast-length", "h, "], - ["valid-time: ", "valid-time", ", "], - ["desc: ", "description", ", "], - ["", "curve-dates", ""], - ], - displayParams: [ - "label", - "group", - "database", - "data-source", - "region", - "statistic", - "variable", - "interp-method", - "scale", - "forecast-length", - "valid-time", - "level", - "description", - "aggregation-method", - "curve-dates", - ], - groupSize: 6, - }); - matsCollections.CurveTextPatterns.insert({ - plotType: matsTypes.PlotTypes.validtime, - textPattern: [ - ["", "label", ": "], - ["", "database", "."], - ["", "data-source", " in "], - ["", "region", ", "], - ["", "threshold", ", "], - ["", "interp-method", " "], - ["", "scale", ", "], - ["", "variable", " "], - ["", "statistic", " "], - ["", "aggregation-method", ", "], - ["level: ", "level", ", "], - ["fcst_len: ", "forecast-length", "h, "], - ["desc: ", "description", ", "], - ["", "curve-dates", ""], - ], - displayParams: [ - "label", - "group", - "database", - "data-source", - "region", - "statistic", - "variable", - "threshold", - "interp-method", - "scale", - "forecast-length", - "level", - "description", - "aggregation-method", - "curve-dates", - ], - groupSize: 6, - }); - matsCollections.CurveTextPatterns.insert({ - plotType: matsTypes.PlotTypes.histogram, - textPattern: [ - ["", "label", ": "], - ["", "database", "."], - ["", "data-source", " in "], - ["", "region", ", "], - ["", "threshold", ", "], - ["", "interp-method", " "], - ["", "scale", ", "], - ["", "variable", " "], - ["", "statistic", ", "], - ["level: ", "level", ", "], - ["fcst_len: ", "forecast-length", "h, "], - ["valid-time: ", "valid-time", ", "], - ["desc: ", "description", ", "], - ["", "curve-dates", ""], - ], - displayParams: [ - "label", - "group", - "database", - "data-source", - "region", - "statistic", - "variable", - "threshold", - "interp-method", - "scale", - "valid-time", - "forecast-length", - "level", - "description", - "curve-dates", - ], - groupSize: 6, - }); - matsCollections.CurveTextPatterns.insert({ - plotType: matsTypes.PlotTypes.contour, - textPattern: [ - ["", "label", ": "], - ["", "database", "."], - ["", "data-source", " in "], - ["", "region", ", "], - ["", "threshold", ", "], - ["", "interp-method", " "], - ["", "scale", ", "], - ["", "variable", " "], - ["", "statistic", " "], - ["", "aggregation-method", ", "], - ["level: ", "level", ", "], - ["fcst_len: ", "forecast-length", "h, "], - ["valid-time: ", "valid-time", ""], - [", desc: ", "description", ""], - ], - displayParams: [ - "label", - "group", - "database", - "data-source", - "region", - "statistic", - "variable", - "threshold", - "interp-method", - "scale", - "valid-time", - "forecast-length", - "level", - "aggregation-method", - "description", - ], - groupSize: 6, - }); - matsCollections.CurveTextPatterns.insert({ - plotType: matsTypes.PlotTypes.simpleScatter, - textPattern: [ - ["", "label", ": "], - ["", "database", "."], - ["", "data-source", " in "], - ["", "region", ", "], - ["", "threshold", ", "], - ["", "interp-method", " "], - ["", "scale", ", "], - ["", "variable", " "], - ["", "statistic", " vs "], - ["", "y-variable", " "], - ["", "y-statistic", ", "], - ["", "aggregation-method", ", "], - ["level: ", "level", ", "], - ["fcst_len: ", "forecast-length", "h, "], - ["valid-time: ", "valid-time", ", "], - [", desc: ", "description", ""], - ], - displayParams: [ - "label", - "group", - "database", - "data-source", - "region", - "statistic", - "variable", - "y-statistic", - "y-variable", - "threshold", - "interp-method", - "scale", - "valid-time", - "forecast-length", - "level", - "description", - "bin-parameter", - "curve-dates", - "aggregation-method", - ], - groupSize: 6, - }); - } -}; - -const doSavedCurveParams = function () { - if ( - matsCollections.Settings.findOne({}) === undefined || - matsCollections.Settings.findOne({}).resetFromCode === undefined || - matsCollections.Settings.findOne({}).resetFromCode === true - ) { - matsCollections.SavedCurveParams.remove({}); - } - if (matsCollections.SavedCurveParams.find().count() === 0) { - matsCollections.SavedCurveParams.insert({ clName: "changeList", changeList: [] }); - } -}; - -const doPlotGraph = function () { - if ( - matsCollections.Settings.findOne({}) === undefined || - matsCollections.Settings.findOne({}).resetFromCode === undefined || - matsCollections.Settings.findOne({}).resetFromCode === true - ) { - matsCollections.PlotGraphFunctions.remove({}); - } - if (matsCollections.PlotGraphFunctions.find().count() === 0) { - matsCollections.PlotGraphFunctions.insert({ - plotType: matsTypes.PlotTypes.timeSeries, - graphFunction: "graphPlotly", - dataFunction: "dataSeries", - checked: true, - }); - matsCollections.PlotGraphFunctions.insert({ - plotType: matsTypes.PlotTypes.dieoff, - graphFunction: "graphPlotly", - dataFunction: "dataDieoff", - checked: false, - }); - matsCollections.PlotGraphFunctions.insert({ - plotType: matsTypes.PlotTypes.threshold, - graphFunction: "graphPlotly", - dataFunction: "dataThreshold", - checked: false, - }); - matsCollections.PlotGraphFunctions.insert({ - plotType: matsTypes.PlotTypes.validtime, - graphFunction: "graphPlotly", - dataFunction: "dataValidTime", - checked: false, - }); - matsCollections.PlotGraphFunctions.insert({ - plotType: matsTypes.PlotTypes.histogram, - graphFunction: "graphPlotly", - dataFunction: "dataHistogram", - checked: false, - }); - matsCollections.PlotGraphFunctions.insert({ - plotType: matsTypes.PlotTypes.contour, - graphFunction: "graphPlotly", - dataFunction: "dataContour", - checked: false, - }); - matsCollections.PlotGraphFunctions.insert({ - plotType: matsTypes.PlotTypes.simpleScatter, - graphFunction: "graphPlotly", - dataFunction: "dataSimpleScatter", - checked: false, - }); - } -}; - -Meteor.startup(function () { - matsCollections.Databases.remove({}); - if (matsCollections.Databases.find({}).count() < 0) { - console.warn( - "main startup: corrupted Databases collection: dropping Databases collection" - ); - matsCollections.Databases.drop(); - } - if (matsCollections.Databases.find({}).count() === 0) { - let databases; - if ( - Meteor.settings === undefined || - Meteor.settings.private === undefined || - Meteor.settings.private.databases === undefined - ) { - databases = undefined; - } else { - databases = Meteor.settings.private.databases; - } - if (databases !== null && databases !== undefined && Array.isArray(databases)) { - for (let di = 0; di < databases.length; di += 1) { - matsCollections.Databases.insert(databases[di]); - } - } - } - - // create list of all pools - const allPools = []; - const sumSettings = matsCollections.Databases.findOne( - { role: matsTypes.DatabaseRoles.SUMS_DATA, status: "active" }, - { - host: 1, - port: 1, - user: 1, - password: 1, - database: 1, - connectionLimit: 1, - } - ); - // the pool is intended to be global - if (sumSettings) { - sumPool = mysql.createPool(sumSettings); - allPools.push({ pool: "sumPool", role: matsTypes.DatabaseRoles.SUMS_DATA }); - } - - // create list of tables we need to monitor for update - const mdr = new matsTypes.MetaDataDBRecord("sumPool", "metexpress_metadata", [ - "airquality_metexpress_metadata", - "airquality_database_groups", - ]); - try { - matsMethods.resetApp({ - appPools: allPools, - appMdr: mdr, - appType: matsTypes.AppTypes.metexpress, - }); - } catch (error) { - throw new Error(error.message); - } -}); - -// this object is global so that the reset code can get to it -// These are application specific mongo data - like curve params -// The appSpecificResetRoutines object is a special name, -// as is doCurveParams. The refreshMetaData mechanism depends on them being named that way. -appSpecificResetRoutines = [ - doPlotGraph, - doCurveParams, - doSavedCurveParams, - doPlotParams, - doCurveTextPatterns, -]; diff --git a/apps/met-anomalycor/.eslintrc.json b/apps/met-anomalycor/.eslintrc.json index a33ac158f..79d49c5bb 100644 --- a/apps/met-anomalycor/.eslintrc.json +++ b/apps/met-anomalycor/.eslintrc.json @@ -28,13 +28,6 @@ "space-before-function-paren": "off", // for Meteor API's that rely on `this` context, e.g. Template.onCreated and publications "func-names": "off", - "prefer-arrow-callback": "off", - - // Vx Team modifications - Warn on rules that would require refactoring to implement. - // We want to be able to turn these back into "error"'s at some point. However, for - // our first pass, we'll only consider the checks that ESLint can auto-fix as errors. - // https://eslint.org/docs/latest/use/configure/rules#rule-severities - "no-undef": "warn", - "no-unused-vars": "warn" + "prefer-arrow-callback": "off" } } diff --git a/apps/met-anomalycor/client/main.js b/apps/met-anomalycor/client/main.js index a87407a1f..ecd922b6a 100644 --- a/apps/met-anomalycor/client/main.js +++ b/apps/met-anomalycor/client/main.js @@ -2,6 +2,7 @@ * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. */ +// eslint-disable-next-line no-unused-vars import { matsTypes, matsCollections, methods } from "meteor/randyp:mats-common"; import "@fortawesome/fontawesome-free"; import "@fortawesome/fontawesome-free/css/all.css"; diff --git a/apps/met-anomalycor/server/dataFunctions/data_contour.js b/apps/met-anomalycor/server/dataFunctions/data_contour.js index 3db18cd7d..17e009b37 100644 --- a/apps/met-anomalycor/server/dataFunctions/data_contour.js +++ b/apps/met-anomalycor/server/dataFunctions/data_contour.js @@ -12,6 +12,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataContour = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -46,9 +47,10 @@ dataContour = function (plotParams, plotFunction) { // initialize variables specific to the curve const curve = curves[0]; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -93,7 +95,8 @@ dataContour = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -284,7 +287,7 @@ dataContour = function (plotParams, plotFunction) { let finishMoment; try { // send the query statement to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-anomalycor/server/dataFunctions/data_dieoff.js b/apps/met-anomalycor/server/dataFunctions/data_dieoff.js index d0afaac1e..5fcb62e5f 100644 --- a/apps/met-anomalycor/server/dataFunctions/data_dieoff.js +++ b/apps/met-anomalycor/server/dataFunctions/data_dieoff.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataDieoff = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataDieoff = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -94,7 +96,8 @@ dataDieoff = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -280,7 +283,7 @@ dataDieoff = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-anomalycor/server/dataFunctions/data_histogram.js b/apps/met-anomalycor/server/dataFunctions/data_histogram.js index 9bfed7b1a..c94cfc507 100644 --- a/apps/met-anomalycor/server/dataFunctions/data_histogram.js +++ b/apps/met-anomalycor/server/dataFunctions/data_histogram.js @@ -11,6 +11,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataHistogram = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -51,9 +52,10 @@ dataHistogram = function (plotParams, plotFunction) { const { diffFrom } = curve; dataFoundForCurve[curveIndex] = true; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -96,7 +98,8 @@ dataHistogram = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -282,7 +285,7 @@ dataHistogram = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-anomalycor/server/dataFunctions/data_profile.js b/apps/met-anomalycor/server/dataFunctions/data_profile.js index 444fef013..f98baa2e3 100644 --- a/apps/met-anomalycor/server/dataFunctions/data_profile.js +++ b/apps/met-anomalycor/server/dataFunctions/data_profile.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataProfile = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -48,9 +49,10 @@ dataProfile = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -93,7 +95,8 @@ dataProfile = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -259,7 +262,7 @@ dataProfile = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-anomalycor/server/dataFunctions/data_series.js b/apps/met-anomalycor/server/dataFunctions/data_series.js index 727758cf3..3db0c44cb 100644 --- a/apps/met-anomalycor/server/dataFunctions/data_series.js +++ b/apps/met-anomalycor/server/dataFunctions/data_series.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataSeries = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -52,9 +53,10 @@ dataSeries = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -97,7 +99,8 @@ dataSeries = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -284,7 +287,7 @@ dataSeries = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-anomalycor/server/dataFunctions/data_simple_scatter.js b/apps/met-anomalycor/server/dataFunctions/data_simple_scatter.js index c0e410e0e..4b9407848 100644 --- a/apps/met-anomalycor/server/dataFunctions/data_simple_scatter.js +++ b/apps/met-anomalycor/server/dataFunctions/data_simple_scatter.js @@ -12,6 +12,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataSimpleScatter = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -46,13 +47,14 @@ dataSimpleScatter = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); const binParam = curve["bin-parameter"]; const binClause = matsCollections["bin-parameter"].findOne({ name: "bin-parameter", }).optionsMap[binParam]; + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const statisticXSelect = curve.statistic; @@ -94,7 +96,8 @@ dataSimpleScatter = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -288,7 +291,7 @@ dataSimpleScatter = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-anomalycor/server/dataFunctions/data_validtime.js b/apps/met-anomalycor/server/dataFunctions/data_validtime.js index 56b51ff88..c2dff54fc 100644 --- a/apps/met-anomalycor/server/dataFunctions/data_validtime.js +++ b/apps/met-anomalycor/server/dataFunctions/data_validtime.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataValidTime = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataValidTime = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -94,7 +96,8 @@ dataValidTime = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -260,7 +263,7 @@ dataValidTime = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-anomalycor/server/main.js b/apps/met-anomalycor/server/main.js index b4883c850..123db6877 100644 --- a/apps/met-anomalycor/server/main.js +++ b/apps/met-anomalycor/server/main.js @@ -386,15 +386,15 @@ const doCurveParams = function () { let dbArr; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select * from anomalycor_database_groups order by db_group;" ); for (let i = 0; i < rows.length; i += 1) { - thisGroup = rows[i].db_group.trim(); + thisGroup = rows[i].db_group.trim().replace(/\./g, "___"); dbs = rows[i].dbs; dbArr = dbs.split(",").map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < dbArr.length; j += 1) { - dbArr[j] = dbArr[j].replace(/'|\[|\]/g, ""); + dbArr[j] = dbArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); } dbGroupMap[thisGroup] = dbArr; } @@ -405,11 +405,11 @@ const doCurveParams = function () { let thisDB; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select distinct db from anomalycor_metexpress_metadata;" ); for (let i = 0; i < rows.length; i += 1) { - thisDB = rows[i].db.trim(); + thisDB = rows[i].db.trim().replace(/\./g, "___"); myDBs.push(thisDB); } } catch (err) { @@ -437,12 +437,12 @@ const doCurveParams = function () { descrOptionsMap[thisDB] = {}; rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef `select model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,interp_mthds,gridpoints,truths,mindate,maxdate from anomalycor_metexpress_metadata where db = '${thisDB}' group by model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,interp_mthds,gridpoints,truths,mindate,maxdate order by model,line_data_table,variable;` ); for (let i = 0; i < rows.length; i += 1) { const modelValue = rows[i].model.trim(); - const model = rows[i].display_text.trim(); + const model = rows[i].display_text.trim().replace(/\./g, "___"); modelOptionsMap[thisDB][model] = [modelValue]; const rowMinDate = moment @@ -466,7 +466,7 @@ const doCurveParams = function () { .split(",") .map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < regionsArr.length; j += 1) { - regionsArr[j] = regionsArr[j].replace(/'|\[|\]/g, ""); + regionsArr[j] = regionsArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); if (regionValueKeys.indexOf(regionsArr[j]) !== -1) { regionsArr[j] = regionValuesMap[regionsArr[j]]; } else { @@ -937,6 +937,8 @@ const doCurveParams = function () { regionDefault = "FULL: Full Domain"; } else if (regionOptions.indexOf("G002") !== -1) { regionDefault = "G002"; + } else if (regionOptions.indexOf("CONUS") !== -1) { + regionDefault = "CONUS"; } else { [regionDefault] = regionOptions; } @@ -2175,6 +2177,7 @@ const doPlotGraph = function () { Meteor.startup(function () { matsCollections.Databases.remove({}); if (matsCollections.Databases.find({}).count() < 0) { + // eslint-disable-next-line no-console console.warn( "main startup: corrupted Databases collection: dropping Databases collection" ); @@ -2213,6 +2216,7 @@ Meteor.startup(function () { ); // the pool is intended to be global if (sumSettings) { + // eslint-disable-next-line no-undef sumPool = mysql.createPool(sumSettings); allPools.push({ pool: "sumPool", role: matsTypes.DatabaseRoles.SUMS_DATA }); } @@ -2237,6 +2241,7 @@ Meteor.startup(function () { // These are application specific mongo data - like curve params // The appSpecificResetRoutines object is a special name, // as is doCurveParams. The refreshMetaData mechanism depends on them being named that way. +// eslint-disable-next-line no-undef appSpecificResetRoutines = [ doPlotGraph, doCurveParams, diff --git a/apps/met-cyclone/.eslintrc.json b/apps/met-cyclone/.eslintrc.json index a33ac158f..79d49c5bb 100644 --- a/apps/met-cyclone/.eslintrc.json +++ b/apps/met-cyclone/.eslintrc.json @@ -28,13 +28,6 @@ "space-before-function-paren": "off", // for Meteor API's that rely on `this` context, e.g. Template.onCreated and publications "func-names": "off", - "prefer-arrow-callback": "off", - - // Vx Team modifications - Warn on rules that would require refactoring to implement. - // We want to be able to turn these back into "error"'s at some point. However, for - // our first pass, we'll only consider the checks that ESLint can auto-fix as errors. - // https://eslint.org/docs/latest/use/configure/rules#rule-severities - "no-undef": "warn", - "no-unused-vars": "warn" + "prefer-arrow-callback": "off" } } diff --git a/apps/met-cyclone/client/main.js b/apps/met-cyclone/client/main.js index a87407a1f..ecd922b6a 100644 --- a/apps/met-cyclone/client/main.js +++ b/apps/met-cyclone/client/main.js @@ -2,6 +2,7 @@ * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. */ +// eslint-disable-next-line no-unused-vars import { matsTypes, matsCollections, methods } from "meteor/randyp:mats-common"; import "@fortawesome/fontawesome-free"; import "@fortawesome/fontawesome-free/css/all.css"; diff --git a/apps/met-cyclone/server/dataFunctions/data_dieoff.js b/apps/met-cyclone/server/dataFunctions/data_dieoff.js index dbff8fa71..abbc6900c 100644 --- a/apps/met-cyclone/server/dataFunctions/data_dieoff.js +++ b/apps/met-cyclone/server/dataFunctions/data_dieoff.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataDieoff = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,7 +50,7 @@ dataDieoff = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) .optionsMap[database][curve["data-source"]][0]; const modelClause = `and h.amodel = '${model}'`; @@ -234,7 +235,7 @@ dataDieoff = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-cyclone/server/dataFunctions/data_histogram.js b/apps/met-cyclone/server/dataFunctions/data_histogram.js index 02ff364bb..667870d78 100644 --- a/apps/met-cyclone/server/dataFunctions/data_histogram.js +++ b/apps/met-cyclone/server/dataFunctions/data_histogram.js @@ -11,6 +11,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataHistogram = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -51,7 +52,7 @@ dataHistogram = function (plotParams, plotFunction) { const { diffFrom } = curve; dataFoundForCurve[curveIndex] = true; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) .optionsMap[database][curve["data-source"]][0]; const modelClause = `and h.amodel = '${model}'`; @@ -236,7 +237,7 @@ dataHistogram = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-cyclone/server/dataFunctions/data_series.js b/apps/met-cyclone/server/dataFunctions/data_series.js index 54e73f798..01488f7b4 100644 --- a/apps/met-cyclone/server/dataFunctions/data_series.js +++ b/apps/met-cyclone/server/dataFunctions/data_series.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataSeries = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -52,7 +53,7 @@ dataSeries = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) .optionsMap[database][curve["data-source"]][0]; const modelClause = `and h.amodel = '${model}'`; @@ -238,7 +239,7 @@ dataSeries = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-cyclone/server/dataFunctions/data_validtime.js b/apps/met-cyclone/server/dataFunctions/data_validtime.js index 73abad5ea..31867909e 100644 --- a/apps/met-cyclone/server/dataFunctions/data_validtime.js +++ b/apps/met-cyclone/server/dataFunctions/data_validtime.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataValidTime = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,7 +50,7 @@ dataValidTime = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) .optionsMap[database][curve["data-source"]][0]; const modelClause = `and h.amodel = '${model}'`; @@ -214,7 +215,7 @@ dataValidTime = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-cyclone/server/dataFunctions/data_yeartoyear.js b/apps/met-cyclone/server/dataFunctions/data_yeartoyear.js index 62937f587..7516ac60c 100644 --- a/apps/met-cyclone/server/dataFunctions/data_yeartoyear.js +++ b/apps/met-cyclone/server/dataFunctions/data_yeartoyear.js @@ -12,6 +12,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataYearToYear = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -48,7 +49,7 @@ dataYearToYear = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) .optionsMap[database][curve["data-source"]][0]; const modelClause = `and h.amodel = '${model}'`; @@ -217,7 +218,7 @@ dataYearToYear = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-cyclone/server/main.js b/apps/met-cyclone/server/main.js index ccf0f865d..6a831a5aa 100644 --- a/apps/met-cyclone/server/main.js +++ b/apps/met-cyclone/server/main.js @@ -801,15 +801,15 @@ const doCurveParams = function () { let dbArr; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select * from cyclone_database_groups order by db_group;" ); for (let i = 0; i < rows.length; i += 1) { - thisGroup = rows[i].db_group.trim(); + thisGroup = rows[i].db_group.trim().replace(/\./g, "___"); dbs = rows[i].dbs; dbArr = dbs.split(",").map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < dbArr.length; j += 1) { - dbArr[j] = dbArr[j].replace(/'|\[|\]/g, ""); + dbArr[j] = dbArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); } dbGroupMap[thisGroup] = dbArr; } @@ -820,11 +820,11 @@ const doCurveParams = function () { let thisDB; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select distinct db from cyclone_metexpress_metadata;" ); for (let i = 0; i < rows.length; i += 1) { - thisDB = rows[i].db.trim(); + thisDB = rows[i].db.trim().replace(/\./g, "___"); myDBs.push(thisDB); } } catch (err) { @@ -847,7 +847,7 @@ const doCurveParams = function () { descrOptionsMap[thisDB] = {}; rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef `select model,display_text,line_data_table,basin,year,storms,truths,levels,descrs,fcst_orig,mindate,maxdate from cyclone_metexpress_metadata where db = '${thisDB}' group by model,display_text,line_data_table,basin,year,storms,truths,levels,descrs,fcst_orig,mindate,maxdate order by model,line_data_table,basin,year desc;` ); for (let i = 0; i < rows.length; i += 1) { @@ -2293,6 +2293,7 @@ const doPlotGraph = function () { Meteor.startup(function () { matsCollections.Databases.remove({}); if (matsCollections.Databases.find({}).count() < 0) { + // eslint-disable-next-line no-console console.warn( "main startup: corrupted Databases collection: dropping Databases collection" ); @@ -2331,6 +2332,7 @@ Meteor.startup(function () { ); // the pool is intended to be global if (sumSettings) { + // eslint-disable-next-line no-undef sumPool = mysql.createPool(sumSettings); allPools.push({ pool: "sumPool", role: matsTypes.DatabaseRoles.SUMS_DATA }); } @@ -2355,6 +2357,7 @@ Meteor.startup(function () { // These are application specific mongo data - like curve params // The appSpecificResetRoutines object is a special name, // as is doCurveParams. The refreshMetaData mechanism depends on them being named that way. +// eslint-disable-next-line no-undef appSpecificResetRoutines = [ doPlotGraph, doCurveParams, diff --git a/apps/met-ensemble/.eslintrc.json b/apps/met-ensemble/.eslintrc.json index a33ac158f..79d49c5bb 100644 --- a/apps/met-ensemble/.eslintrc.json +++ b/apps/met-ensemble/.eslintrc.json @@ -28,13 +28,6 @@ "space-before-function-paren": "off", // for Meteor API's that rely on `this` context, e.g. Template.onCreated and publications "func-names": "off", - "prefer-arrow-callback": "off", - - // Vx Team modifications - Warn on rules that would require refactoring to implement. - // We want to be able to turn these back into "error"'s at some point. However, for - // our first pass, we'll only consider the checks that ESLint can auto-fix as errors. - // https://eslint.org/docs/latest/use/configure/rules#rule-severities - "no-undef": "warn", - "no-unused-vars": "warn" + "prefer-arrow-callback": "off" } } diff --git a/apps/met-ensemble/client/main.js b/apps/met-ensemble/client/main.js index a87407a1f..ecd922b6a 100644 --- a/apps/met-ensemble/client/main.js +++ b/apps/met-ensemble/client/main.js @@ -2,6 +2,7 @@ * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. */ +// eslint-disable-next-line no-unused-vars import { matsTypes, matsCollections, methods } from "meteor/randyp:mats-common"; import "@fortawesome/fontawesome-free"; import "@fortawesome/fontawesome-free/css/all.css"; diff --git a/apps/met-ensemble/server/dataFunctions/data_dieoff.js b/apps/met-ensemble/server/dataFunctions/data_dieoff.js index 52f951cb1..a36e58064 100644 --- a/apps/met-ensemble/server/dataFunctions/data_dieoff.js +++ b/apps/met-ensemble/server/dataFunctions/data_dieoff.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataDieoff = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataDieoff = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -82,7 +84,7 @@ dataDieoff = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -246,7 +248,7 @@ dataDieoff = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-ensemble/server/dataFunctions/data_ensemble_histogram.js b/apps/met-ensemble/server/dataFunctions/data_ensemble_histogram.js index d085f6263..b971883ec 100644 --- a/apps/met-ensemble/server/dataFunctions/data_ensemble_histogram.js +++ b/apps/met-ensemble/server/dataFunctions/data_ensemble_histogram.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataEnsembleHistogram = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -51,9 +52,10 @@ dataEnsembleHistogram = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; let statistic; @@ -88,7 +90,7 @@ dataEnsembleHistogram = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -249,7 +251,7 @@ dataEnsembleHistogram = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-ensemble/server/dataFunctions/data_histogram.js b/apps/met-ensemble/server/dataFunctions/data_histogram.js index 61f265a01..12967a709 100644 --- a/apps/met-ensemble/server/dataFunctions/data_histogram.js +++ b/apps/met-ensemble/server/dataFunctions/data_histogram.js @@ -11,6 +11,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataHistogram = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -51,9 +52,10 @@ dataHistogram = function (plotParams, plotFunction) { const { diffFrom } = curve; dataFoundForCurve[curveIndex] = true; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -84,7 +86,7 @@ dataHistogram = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -248,7 +250,7 @@ dataHistogram = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-ensemble/server/dataFunctions/data_perfDiagram.js b/apps/met-ensemble/server/dataFunctions/data_perfDiagram.js index 53cbe4044..8309fc0bf 100644 --- a/apps/met-ensemble/server/dataFunctions/data_perfDiagram.js +++ b/apps/met-ensemble/server/dataFunctions/data_perfDiagram.js @@ -12,6 +12,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataPerformanceDiagram = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -46,9 +47,10 @@ dataPerformanceDiagram = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const statistic = "PerformanceDiagram"; @@ -70,7 +72,7 @@ dataPerformanceDiagram = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -232,7 +234,7 @@ dataPerformanceDiagram = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-ensemble/server/dataFunctions/data_reliability.js b/apps/met-ensemble/server/dataFunctions/data_reliability.js index 59bff2463..d2ba36355 100644 --- a/apps/met-ensemble/server/dataFunctions/data_reliability.js +++ b/apps/met-ensemble/server/dataFunctions/data_reliability.js @@ -12,6 +12,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataReliability = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataReliability = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const statistic = "Reliability"; @@ -73,7 +75,7 @@ dataReliability = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -232,7 +234,7 @@ dataReliability = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-ensemble/server/dataFunctions/data_roc.js b/apps/met-ensemble/server/dataFunctions/data_roc.js index 3aa515f46..87f04b010 100644 --- a/apps/met-ensemble/server/dataFunctions/data_roc.js +++ b/apps/met-ensemble/server/dataFunctions/data_roc.js @@ -12,6 +12,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataROC = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -46,9 +47,10 @@ dataROC = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const statistic = "ROC"; @@ -70,7 +72,7 @@ dataROC = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -232,7 +234,7 @@ dataROC = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-ensemble/server/dataFunctions/data_series.js b/apps/met-ensemble/server/dataFunctions/data_series.js index 9a19302b3..67093721f 100644 --- a/apps/met-ensemble/server/dataFunctions/data_series.js +++ b/apps/met-ensemble/server/dataFunctions/data_series.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataSeries = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -52,9 +53,10 @@ dataSeries = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -85,7 +87,7 @@ dataSeries = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -250,7 +252,7 @@ dataSeries = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-ensemble/server/dataFunctions/data_validtime.js b/apps/met-ensemble/server/dataFunctions/data_validtime.js index 0e3212dad..bb1761802 100644 --- a/apps/met-ensemble/server/dataFunctions/data_validtime.js +++ b/apps/met-ensemble/server/dataFunctions/data_validtime.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataValidTime = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataValidTime = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -82,7 +84,7 @@ dataValidTime = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -226,7 +228,7 @@ dataValidTime = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-ensemble/server/main.js b/apps/met-ensemble/server/main.js index 058514e39..76b27ba94 100644 --- a/apps/met-ensemble/server/main.js +++ b/apps/met-ensemble/server/main.js @@ -398,15 +398,15 @@ const doCurveParams = function () { let dbArr; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select * from ensemble_database_groups order by db_group;" ); for (let i = 0; i < rows.length; i += 1) { - thisGroup = rows[i].db_group.trim(); + thisGroup = rows[i].db_group.trim().replace(/\./g, "___"); dbs = rows[i].dbs; dbArr = dbs.split(",").map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < dbArr.length; j += 1) { - dbArr[j] = dbArr[j].replace(/'|\[|\]/g, ""); + dbArr[j] = dbArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); } dbGroupMap[thisGroup] = dbArr; } @@ -417,11 +417,11 @@ const doCurveParams = function () { let thisDB; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select distinct db from ensemble_metexpress_metadata;" ); for (let i = 0; i < rows.length; i += 1) { - thisDB = rows[i].db.trim(); + thisDB = rows[i].db.trim().replace(/\./g, "___"); myDBs.push(thisDB); } } catch (err) { @@ -443,12 +443,12 @@ const doCurveParams = function () { descrOptionsMap[thisDB] = {}; rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef `select model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,mindate,maxdate from ensemble_metexpress_metadata where db = '${thisDB}' group by model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,mindate,maxdate order by model,line_data_table,variable;` ); for (let i = 0; i < rows.length; i += 1) { const modelValue = rows[i].model.trim(); - const model = rows[i].display_text.trim(); + const model = rows[i].display_text.trim().replace(/\./g, "___"); modelOptionsMap[thisDB][model] = [modelValue]; const rowMinDate = moment @@ -472,7 +472,7 @@ const doCurveParams = function () { .split(",") .map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < regionsArr.length; j += 1) { - regionsArr[j] = regionsArr[j].replace(/'|\[|\]/g, ""); + regionsArr[j] = regionsArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); } const forecastLengths = rows[i].fcst_orig; @@ -1791,6 +1791,7 @@ const doPlotGraph = function () { Meteor.startup(function () { matsCollections.Databases.remove({}); if (matsCollections.Databases.find({}).count() < 0) { + // eslint-disable-next-line no-console console.warn( "main startup: corrupted Databases collection: dropping Databases collection" ); @@ -1829,6 +1830,7 @@ Meteor.startup(function () { ); // the pool is intended to be global if (sumSettings) { + // eslint-disable-next-line no-undef sumPool = mysql.createPool(sumSettings); allPools.push({ pool: "sumPool", role: matsTypes.DatabaseRoles.SUMS_DATA }); } @@ -1853,6 +1855,7 @@ Meteor.startup(function () { // These are application specific mongo data - like curve params // The appSpecificResetRoutines object is a special name, // as is doCurveParams. The refreshMetaData mechanism depends on them being named that way. +// eslint-disable-next-line no-undef appSpecificResetRoutines = [ doPlotGraph, doCurveParams, diff --git a/apps/met-object/.eslintrc.json b/apps/met-object/.eslintrc.json index a33ac158f..79d49c5bb 100644 --- a/apps/met-object/.eslintrc.json +++ b/apps/met-object/.eslintrc.json @@ -28,13 +28,6 @@ "space-before-function-paren": "off", // for Meteor API's that rely on `this` context, e.g. Template.onCreated and publications "func-names": "off", - "prefer-arrow-callback": "off", - - // Vx Team modifications - Warn on rules that would require refactoring to implement. - // We want to be able to turn these back into "error"'s at some point. However, for - // our first pass, we'll only consider the checks that ESLint can auto-fix as errors. - // https://eslint.org/docs/latest/use/configure/rules#rule-severities - "no-undef": "warn", - "no-unused-vars": "warn" + "prefer-arrow-callback": "off" } } diff --git a/apps/met-object/client/main.js b/apps/met-object/client/main.js index a87407a1f..ecd922b6a 100644 --- a/apps/met-object/client/main.js +++ b/apps/met-object/client/main.js @@ -2,6 +2,7 @@ * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. */ +// eslint-disable-next-line no-unused-vars import { matsTypes, matsCollections, methods } from "meteor/randyp:mats-common"; import "@fortawesome/fontawesome-free"; import "@fortawesome/fontawesome-free/css/all.css"; diff --git a/apps/met-object/server/dataFunctions/data_dieoff.js b/apps/met-object/server/dataFunctions/data_dieoff.js index 3000301cc..f2c706c22 100644 --- a/apps/met-object/server/dataFunctions/data_dieoff.js +++ b/apps/met-object/server/dataFunctions/data_dieoff.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataDieoff = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataDieoff = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -283,7 +285,7 @@ dataDieoff = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-object/server/dataFunctions/data_series.js b/apps/met-object/server/dataFunctions/data_series.js index 5b6722ffb..71ef3fbc4 100644 --- a/apps/met-object/server/dataFunctions/data_series.js +++ b/apps/met-object/server/dataFunctions/data_series.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataSeries = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -52,9 +53,10 @@ dataSeries = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -287,7 +289,7 @@ dataSeries = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-object/server/dataFunctions/data_threshold.js b/apps/met-object/server/dataFunctions/data_threshold.js index 3701ca444..16ee51fe1 100644 --- a/apps/met-object/server/dataFunctions/data_threshold.js +++ b/apps/met-object/server/dataFunctions/data_threshold.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataThreshold = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataThreshold = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -275,7 +277,7 @@ dataThreshold = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-object/server/dataFunctions/data_validtime.js b/apps/met-object/server/dataFunctions/data_validtime.js index a1fc8995e..94167c5d3 100644 --- a/apps/met-object/server/dataFunctions/data_validtime.js +++ b/apps/met-object/server/dataFunctions/data_validtime.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataValidTime = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataValidTime = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -263,7 +265,7 @@ dataValidTime = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-object/server/main.js b/apps/met-object/server/main.js index c33beb56a..8090d550c 100644 --- a/apps/met-object/server/main.js +++ b/apps/met-object/server/main.js @@ -285,15 +285,15 @@ const doCurveParams = function () { let dbArr; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select * from mode_database_groups order by db_group;" ); for (let i = 0; i < rows.length; i += 1) { - thisGroup = rows[i].db_group.trim(); + thisGroup = rows[i].db_group.trim().replace(/\./g, "___"); dbs = rows[i].dbs; dbArr = dbs.split(",").map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < dbArr.length; j += 1) { - dbArr[j] = dbArr[j].replace(/'|\[|\]/g, ""); + dbArr[j] = dbArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); } dbGroupMap[thisGroup] = dbArr; } @@ -304,11 +304,11 @@ const doCurveParams = function () { let thisDB; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select distinct db from mode_metexpress_metadata;" ); for (let i = 0; i < rows.length; i += 1) { - thisDB = rows[i].db.trim(); + thisDB = rows[i].db.trim().replace(/\./g, "___"); myDBs.push(thisDB); } } catch (err) { @@ -332,12 +332,12 @@ const doCurveParams = function () { descrOptionsMap[thisDB] = {}; rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef `select model,display_text,line_data_table,variable,levels,descrs,fcst_orig,trshs,radii,gridpoints,mindate,maxdate from mode_metexpress_metadata where db = '${thisDB}' group by model,display_text,line_data_table,variable,levels,descrs,fcst_orig,trshs,radii,gridpoints,mindate,maxdate order by model,line_data_table,variable;` ); for (let i = 0; i < rows.length; i += 1) { const modelValue = rows[i].model.trim(); - const model = rows[i].display_text.trim(); + const model = rows[i].display_text.trim().replace(/\./g, "___"); modelOptionsMap[thisDB][model] = [modelValue]; const rowMinDate = moment @@ -1931,6 +1931,7 @@ const doPlotGraph = function () { Meteor.startup(function () { matsCollections.Databases.remove({}); if (matsCollections.Databases.find({}).count() < 0) { + // eslint-disable-next-line no-console console.warn( "main startup: corrupted Databases collection: dropping Databases collection" ); @@ -1969,6 +1970,7 @@ Meteor.startup(function () { ); // the pool is intended to be global if (sumSettings) { + // eslint-disable-next-line no-undef sumPool = mysql.createPool(sumSettings); allPools.push({ pool: "sumPool", role: matsTypes.DatabaseRoles.SUMS_DATA }); } @@ -1993,6 +1995,7 @@ Meteor.startup(function () { // These are application specific mongo data - like curve params // The appSpecificResetRoutines object is a special name, // as is doCurveParams. The refreshMetaData mechanism depends on them being named that way. +// eslint-disable-next-line no-undef appSpecificResetRoutines = [ doPlotGraph, doCurveParams, diff --git a/apps/met-precip/.eslintrc.json b/apps/met-precip/.eslintrc.json index a33ac158f..79d49c5bb 100644 --- a/apps/met-precip/.eslintrc.json +++ b/apps/met-precip/.eslintrc.json @@ -28,13 +28,6 @@ "space-before-function-paren": "off", // for Meteor API's that rely on `this` context, e.g. Template.onCreated and publications "func-names": "off", - "prefer-arrow-callback": "off", - - // Vx Team modifications - Warn on rules that would require refactoring to implement. - // We want to be able to turn these back into "error"'s at some point. However, for - // our first pass, we'll only consider the checks that ESLint can auto-fix as errors. - // https://eslint.org/docs/latest/use/configure/rules#rule-severities - "no-undef": "warn", - "no-unused-vars": "warn" + "prefer-arrow-callback": "off" } } diff --git a/apps/met-precip/client/main.js b/apps/met-precip/client/main.js index a87407a1f..ecd922b6a 100644 --- a/apps/met-precip/client/main.js +++ b/apps/met-precip/client/main.js @@ -2,6 +2,7 @@ * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. */ +// eslint-disable-next-line no-unused-vars import { matsTypes, matsCollections, methods } from "meteor/randyp:mats-common"; import "@fortawesome/fontawesome-free"; import "@fortawesome/fontawesome-free/css/all.css"; diff --git a/apps/met-precip/server/dataFunctions/data_contour.js b/apps/met-precip/server/dataFunctions/data_contour.js index 40b7933e1..9699574b5 100644 --- a/apps/met-precip/server/dataFunctions/data_contour.js +++ b/apps/met-precip/server/dataFunctions/data_contour.js @@ -12,6 +12,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataContour = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -46,9 +47,10 @@ dataContour = function (plotParams, plotFunction) { // initialize variables specific to the curve const curve = curves[0]; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -98,7 +100,7 @@ dataContour = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -291,7 +293,7 @@ dataContour = function (plotParams, plotFunction) { let finishMoment; try { // send the query statement to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-precip/server/dataFunctions/data_dieoff.js b/apps/met-precip/server/dataFunctions/data_dieoff.js index 033753d79..efc411e9d 100644 --- a/apps/met-precip/server/dataFunctions/data_dieoff.js +++ b/apps/met-precip/server/dataFunctions/data_dieoff.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataDieoff = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataDieoff = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -97,7 +99,7 @@ dataDieoff = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -292,7 +294,7 @@ dataDieoff = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-precip/server/dataFunctions/data_gridscale.js b/apps/met-precip/server/dataFunctions/data_gridscale.js index bfbcab73d..9ffec3e34 100644 --- a/apps/met-precip/server/dataFunctions/data_gridscale.js +++ b/apps/met-precip/server/dataFunctions/data_gridscale.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataGridScale = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataGridScale = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -97,7 +99,7 @@ dataGridScale = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -281,7 +283,7 @@ dataGridScale = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-precip/server/dataFunctions/data_histogram.js b/apps/met-precip/server/dataFunctions/data_histogram.js index ea49fe4f8..ace5546bb 100644 --- a/apps/met-precip/server/dataFunctions/data_histogram.js +++ b/apps/met-precip/server/dataFunctions/data_histogram.js @@ -11,6 +11,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataHistogram = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -51,9 +52,10 @@ dataHistogram = function (plotParams, plotFunction) { const { diffFrom } = curve; dataFoundForCurve[curveIndex] = true; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -99,7 +101,7 @@ dataHistogram = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -291,7 +293,7 @@ dataHistogram = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-precip/server/dataFunctions/data_series.js b/apps/met-precip/server/dataFunctions/data_series.js index d6862f43e..467cc3670 100644 --- a/apps/met-precip/server/dataFunctions/data_series.js +++ b/apps/met-precip/server/dataFunctions/data_series.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataSeries = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -52,9 +53,10 @@ dataSeries = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -100,7 +102,7 @@ dataSeries = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -296,7 +298,7 @@ dataSeries = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-precip/server/dataFunctions/data_threshold.js b/apps/met-precip/server/dataFunctions/data_threshold.js index 1bc936b6c..d7dbf49a5 100644 --- a/apps/met-precip/server/dataFunctions/data_threshold.js +++ b/apps/met-precip/server/dataFunctions/data_threshold.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataThreshold = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataThreshold = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -97,7 +99,7 @@ dataThreshold = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -284,7 +286,7 @@ dataThreshold = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-precip/server/dataFunctions/data_validtime.js b/apps/met-precip/server/dataFunctions/data_validtime.js index 9c54a5de7..c79e81b40 100644 --- a/apps/met-precip/server/dataFunctions/data_validtime.js +++ b/apps/met-precip/server/dataFunctions/data_validtime.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataValidTime = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataValidTime = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -97,7 +99,7 @@ dataValidTime = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${r.replace(/___/g, ".")}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -272,7 +274,7 @@ dataValidTime = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-precip/server/main.js b/apps/met-precip/server/main.js index 69f1258fb..b7b1bab09 100644 --- a/apps/met-precip/server/main.js +++ b/apps/met-precip/server/main.js @@ -422,15 +422,15 @@ const doCurveParams = function () { let dbArr; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select * from precip_database_groups order by db_group;" ); for (let i = 0; i < rows.length; i += 1) { - thisGroup = rows[i].db_group.trim(); + thisGroup = rows[i].db_group.trim().replace(/\./g, "___"); dbs = rows[i].dbs; dbArr = dbs.split(",").map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < dbArr.length; j += 1) { - dbArr[j] = dbArr[j].replace(/'|\[|\]/g, ""); + dbArr[j] = dbArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); } dbGroupMap[thisGroup] = dbArr; } @@ -441,11 +441,11 @@ const doCurveParams = function () { let thisDB; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select distinct db from precip_metexpress_metadata;" ); for (let i = 0; i < rows.length; i += 1) { - thisDB = rows[i].db.trim(); + thisDB = rows[i].db.trim().replace(/\./g, "___"); myDBs.push(thisDB); } } catch (err) { @@ -471,12 +471,12 @@ const doCurveParams = function () { descrOptionsMap[thisDB] = {}; rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef `select model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,trshs,interp_mthds,gridpoints,truths,mindate,maxdate from precip_metexpress_metadata where db = '${thisDB}' group by model,display_text,line_data_table,variable,regions,levels,descrs,fcst_lens,fcst_orig,trshs,interp_mthds,gridpoints,truths,mindate,maxdate order by model,line_data_table,variable;` ); for (let i = 0; i < rows.length; i += 1) { const modelValue = rows[i].model.trim(); - const model = rows[i].display_text.trim(); + const model = rows[i].display_text.trim().replace(/\./g, "___"); modelOptionsMap[thisDB][model] = [modelValue]; const rowMinDate = moment @@ -500,7 +500,7 @@ const doCurveParams = function () { .split(",") .map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < regionsArr.length; j += 1) { - regionsArr[j] = regionsArr[j].replace(/'|\[|\]/g, ""); + regionsArr[j] = regionsArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); } const sources = rows[i].truths; @@ -993,8 +993,6 @@ const doCurveParams = function () { regionDefault = "G002"; } else if (regionOptions.indexOf("CONUS") !== -1) { regionDefault = "CONUS"; - } else if (regionOptions.indexOf("G218/APL") !== -1) { - regionDefault = "G218/APL"; } else { [regionDefault] = regionOptions; } @@ -2211,6 +2209,7 @@ const doPlotGraph = function () { Meteor.startup(function () { matsCollections.Databases.remove({}); if (matsCollections.Databases.find({}).count() < 0) { + // eslint-disable-next-line no-console console.warn( "main startup: corrupted Databases collection: dropping Databases collection" ); @@ -2249,6 +2248,7 @@ Meteor.startup(function () { ); // the pool is intended to be global if (sumSettings) { + // eslint-disable-next-line no-undef sumPool = mysql.createPool(sumSettings); allPools.push({ pool: "sumPool", role: matsTypes.DatabaseRoles.SUMS_DATA }); } @@ -2273,6 +2273,7 @@ Meteor.startup(function () { // These are application specific mongo data - like curve params // The appSpecificResetRoutines object is a special name, // as is doCurveParams. The refreshMetaData mechanism depends on them being named that way. +// eslint-disable-next-line no-undef appSpecificResetRoutines = [ doPlotGraph, doCurveParams, diff --git a/apps/met-surface/.eslintrc.json b/apps/met-surface/.eslintrc.json index a33ac158f..79d49c5bb 100644 --- a/apps/met-surface/.eslintrc.json +++ b/apps/met-surface/.eslintrc.json @@ -28,13 +28,6 @@ "space-before-function-paren": "off", // for Meteor API's that rely on `this` context, e.g. Template.onCreated and publications "func-names": "off", - "prefer-arrow-callback": "off", - - // Vx Team modifications - Warn on rules that would require refactoring to implement. - // We want to be able to turn these back into "error"'s at some point. However, for - // our first pass, we'll only consider the checks that ESLint can auto-fix as errors. - // https://eslint.org/docs/latest/use/configure/rules#rule-severities - "no-undef": "warn", - "no-unused-vars": "warn" + "prefer-arrow-callback": "off" } } diff --git a/apps/met-surface/client/main.js b/apps/met-surface/client/main.js index a87407a1f..ecd922b6a 100644 --- a/apps/met-surface/client/main.js +++ b/apps/met-surface/client/main.js @@ -2,6 +2,7 @@ * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. */ +// eslint-disable-next-line no-unused-vars import { matsTypes, matsCollections, methods } from "meteor/randyp:mats-common"; import "@fortawesome/fontawesome-free"; import "@fortawesome/fontawesome-free/css/all.css"; diff --git a/apps/met-surface/server/dataFunctions/data_contour.js b/apps/met-surface/server/dataFunctions/data_contour.js index 907a92e3f..443362730 100644 --- a/apps/met-surface/server/dataFunctions/data_contour.js +++ b/apps/met-surface/server/dataFunctions/data_contour.js @@ -12,6 +12,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataContour = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -46,9 +47,10 @@ dataContour = function (plotParams, plotFunction) { // initialize variables specific to the curve const curve = curves[0]; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -78,6 +80,15 @@ dataContour = function (plotParams, plotFunction) { "ld.uvfobar, ';', ld.uvffbar, ';', ld.uvoobar, ';', ld.f_speed_bar, ';', ld.o_speed_bar, ';', " + "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; lineDataType = "line_data_vl1l2"; + } else if (statLineType === "ctc") { + statisticClause = + "count(ld.fy_oy) as n, " + + "sum(ld.fy_oy) as fy_oy, " + + "sum(ld.fy_on) as fy_on, " + + "sum(ld.fn_oy) as fn_oy, " + + "sum(ld.fn_on) as fn_on, " + + "group_concat(distinct ld.fy_oy, ';', ld.fy_on, ';', ld.fn_oy, ';', ld.fn_on, ';', ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; + lineDataType = "line_data_ctc"; } const queryTableClause = `from ${database}.stat_header h, ${database}.${lineDataType} ld`; let regions = @@ -93,7 +104,8 @@ dataContour = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -115,6 +127,11 @@ dataContour = function (plotParams, plotFunction) { { valuesMap: 1 } ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; const variableClause = `and h.fcst_var = '${variableValuesMap[variable]}'`; + const { threshold } = curve; + let thresholdClause = ""; + if (threshold !== "All thresholds") { + thresholdClause = `and h.fcst_thresh = '${threshold}'`; + } const { truth } = curve; let truthClause = ""; if (truth !== "Any truth dataset") { @@ -211,7 +228,10 @@ dataContour = function (plotParams, plotFunction) { descrsClause = `and h.descr IN(${descrs})`; } appParams.aggMethod = curve["aggregation-method"]; - const statType = `met-${statLineType}`; + const statType = + curve["aggregation-method"] === "Overall statistic" && statLineType === "ctc" + ? statLineType + : `met-${statLineType}`; allStatTypes.push(statType); // For contours, this functions as the colorbar label. let unitKey; @@ -253,6 +273,7 @@ dataContour = function (plotParams, plotFunction) { "{{imClause}} " + "{{scaleClause}} " + "{{variableClause}} " + + "{{thresholdClause}} " + "{{truthClause}} " + "{{validTimeClause}} " + "{{forecastLengthsClause}} " + @@ -272,6 +293,7 @@ dataContour = function (plotParams, plotFunction) { statement = statement.replace("{{imClause}}", imClause); statement = statement.replace("{{scaleClause}}", scaleClause); statement = statement.replace("{{variableClause}}", variableClause); + statement = statement.replace("{{thresholdClause}}", thresholdClause); statement = statement.replace("{{truthClause}}", truthClause); statement = statement.replace("{{validTimeClause}}", validTimeClause); statement = statement.replace("{{forecastLengthsClause}}", forecastLengthsClause); @@ -297,7 +319,7 @@ dataContour = function (plotParams, plotFunction) { let finishMoment; try { // send the query statement to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-surface/server/dataFunctions/data_dieoff.js b/apps/met-surface/server/dataFunctions/data_dieoff.js index e9ebb47b5..e93b507a7 100644 --- a/apps/met-surface/server/dataFunctions/data_dieoff.js +++ b/apps/met-surface/server/dataFunctions/data_dieoff.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataDieoff = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -50,9 +51,10 @@ dataDieoff = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -80,6 +82,14 @@ dataDieoff = function (plotParams, plotFunction) { "ld.uvfobar, ';', ld.uvffbar, ';', ld.uvoobar, ';', ld.f_speed_bar, ';', ld.o_speed_bar, ';', " + "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; lineDataType = "line_data_vl1l2"; + } else if (statLineType === "ctc") { + statisticClause = + "sum(ld.fy_oy) as fy_oy, " + + "sum(ld.fy_on) as fy_on, " + + "sum(ld.fn_oy) as fn_oy, " + + "sum(ld.fn_on) as fn_on, " + + "group_concat(distinct ld.fy_oy, ';', ld.fy_on, ';', ld.fn_oy, ';', ld.fn_on, ';', ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; + lineDataType = "line_data_ctc"; } const queryTableClause = `from ${database}.stat_header h, ${database}.${lineDataType} ld`; let regions = @@ -91,7 +101,13 @@ dataDieoff = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${Object.keys( + matsCollections.region.findOne({ name: "region" }).valuesMap + ).find( + (key) => + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") + )}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -112,6 +128,11 @@ dataDieoff = function (plotParams, plotFunction) { { valuesMap: 1 } ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; const variableClause = `and h.fcst_var = '${variableValuesMap[variable]}'`; + const { threshold } = curve; + let thresholdClause = ""; + if (threshold !== "All thresholds") { + thresholdClause = `and h.fcst_thresh = '${threshold}'`; + } const { truth } = curve; let truthClause = ""; if (truth !== "Any truth dataset") { @@ -200,7 +221,10 @@ dataDieoff = function (plotParams, plotFunction) { .join(","); descrsClause = `and h.descr IN(${descrs})`; } - const statType = `met-${statLineType}`; + const statType = + curve["aggregation-method"] === "Overall statistic" && statLineType === "ctc" + ? statLineType + : `met-${statLineType}`; allStatTypes.push(statType); appParams.aggMethod = curve["aggregation-method"]; // axisKey is used to determine which axis a curve should use. @@ -246,6 +270,7 @@ dataDieoff = function (plotParams, plotFunction) { "{{imClause}} " + "{{scaleClause}} " + "{{variableClause}} " + + "{{thresholdClause}} " + "{{truthClause}} " + "{{validTimeClause}} " + "{{utcCycleStartClause}} " + @@ -263,6 +288,7 @@ dataDieoff = function (plotParams, plotFunction) { statement = statement.replace("{{imClause}}", imClause); statement = statement.replace("{{scaleClause}}", scaleClause); statement = statement.replace("{{variableClause}}", variableClause); + statement = statement.replace("{{thresholdClause}}", thresholdClause); statement = statement.replace("{{truthClause}}", truthClause); statement = statement.replace("{{validTimeClause}}", validTimeClause); statement = statement.replace("{{utcCycleStartClause}}", utcCycleStartClause); @@ -294,7 +320,7 @@ dataDieoff = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-surface/server/dataFunctions/data_histogram.js b/apps/met-surface/server/dataFunctions/data_histogram.js index 78683a7da..5572656ed 100644 --- a/apps/met-surface/server/dataFunctions/data_histogram.js +++ b/apps/met-surface/server/dataFunctions/data_histogram.js @@ -11,6 +11,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataHistogram = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -51,9 +52,10 @@ dataHistogram = function (plotParams, plotFunction) { const { diffFrom } = curve; dataFoundForCurve[curveIndex] = true; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -81,6 +83,14 @@ dataHistogram = function (plotParams, plotFunction) { "ld.uvfobar, ';', ld.uvffbar, ';', ld.uvoobar, ';', ld.f_speed_bar, ';', ld.o_speed_bar, ';', " + "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; lineDataType = "line_data_vl1l2"; + } else if (statLineType === "ctc") { + statisticClause = + "sum(ld.fy_oy) as fy_oy, " + + "sum(ld.fy_on) as fy_on, " + + "sum(ld.fn_oy) as fn_oy, " + + "sum(ld.fn_on) as fn_on, " + + "group_concat(distinct ld.fy_oy, ';', ld.fy_on, ';', ld.fn_oy, ';', ld.fn_on, ';', ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; + lineDataType = "line_data_ctc"; } const queryTableClause = `from ${database}.stat_header h, ${database}.${lineDataType} ld`; let regions = @@ -96,7 +106,8 @@ dataHistogram = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -118,6 +129,11 @@ dataHistogram = function (plotParams, plotFunction) { { valuesMap: 1 } ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; const variableClause = `and h.fcst_var = '${variableValuesMap[variable]}'`; + const { threshold } = curve; + let thresholdClause = ""; + if (threshold !== "All thresholds") { + thresholdClause = `and h.fcst_thresh = '${threshold}'`; + } const { truth } = curve; let truthClause = ""; if (truth !== "Any truth dataset") { @@ -234,6 +250,7 @@ dataHistogram = function (plotParams, plotFunction) { "{{imClause}} " + "{{scaleClause}} " + "{{variableClause}} " + + "{{thresholdClause}} " + "{{truthClause}} " + "{{validTimeClause}} " + "{{forecastLengthsClause}} " + @@ -251,6 +268,7 @@ dataHistogram = function (plotParams, plotFunction) { statement = statement.replace("{{imClause}}", imClause); statement = statement.replace("{{scaleClause}}", scaleClause); statement = statement.replace("{{variableClause}}", variableClause); + statement = statement.replace("{{thresholdClause}}", thresholdClause); statement = statement.replace("{{truthClause}}", truthClause); statement = statement.replace("{{validTimeClause}}", validTimeClause); statement = statement.replace("{{forecastLengthsClause}}", forecastLengthsClause); @@ -282,7 +300,7 @@ dataHistogram = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-surface/server/dataFunctions/data_series.js b/apps/met-surface/server/dataFunctions/data_series.js index 87d68d018..8eab2913b 100644 --- a/apps/met-surface/server/dataFunctions/data_series.js +++ b/apps/met-surface/server/dataFunctions/data_series.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataSeries = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -53,9 +54,10 @@ dataSeries = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -83,6 +85,14 @@ dataSeries = function (plotParams, plotFunction) { "ld.uvfobar, ';', ld.uvffbar, ';', ld.uvoobar, ';', ld.f_speed_bar, ';', ld.o_speed_bar, ';', " + "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; lineDataType = "line_data_vl1l2"; + } else if (statLineType === "ctc") { + statisticClause = + "sum(ld.fy_oy) as fy_oy, " + + "sum(ld.fy_on) as fy_on, " + + "sum(ld.fn_oy) as fn_oy, " + + "sum(ld.fn_on) as fn_on, " + + "group_concat(distinct ld.fy_oy, ';', ld.fy_on, ';', ld.fn_oy, ';', ld.fn_on, ';', ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; + lineDataType = "line_data_ctc"; } const queryTableClause = `from ${database}.stat_header h, ${database}.${lineDataType} ld`; let regions = @@ -98,7 +108,8 @@ dataSeries = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -120,6 +131,11 @@ dataSeries = function (plotParams, plotFunction) { { valuesMap: 1 } ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; const variableClause = `and h.fcst_var = '${variableValuesMap[variable]}'`; + const { threshold } = curve; + let thresholdClause = ""; + if (threshold !== "All thresholds") { + thresholdClause = `and h.fcst_thresh = '${threshold}'`; + } const { truth } = curve; let truthClause = ""; if (truth !== "Any truth dataset") { @@ -208,7 +224,10 @@ dataSeries = function (plotParams, plotFunction) { { optionsMap: 1 } ).optionsMap; const average = averageOptionsMap[averageStr][0]; - const statType = `met-${statLineType}`; + const statType = + curve["aggregation-method"] === "Overall statistic" && statLineType === "ctc" + ? statLineType + : `met-${statLineType}`; allStatTypes.push(statType); appParams.aggMethod = curve["aggregation-method"]; // axisKey is used to determine which axis a curve should use. @@ -254,6 +273,7 @@ dataSeries = function (plotParams, plotFunction) { "{{imClause}} " + "{{scaleClause}} " + "{{variableClause}} " + + "{{thresholdClause}} " + "{{truthClause}} " + "{{validTimeClause}} " + "{{forecastLengthsClause}} " + @@ -272,6 +292,7 @@ dataSeries = function (plotParams, plotFunction) { statement = statement.replace("{{imClause}}", imClause); statement = statement.replace("{{scaleClause}}", scaleClause); statement = statement.replace("{{variableClause}}", variableClause); + statement = statement.replace("{{thresholdClause}}", thresholdClause); statement = statement.replace("{{truthClause}}", truthClause); statement = statement.replace("{{validTimeClause}}", validTimeClause); statement = statement.replace("{{forecastLengthsClause}}", forecastLengthsClause); @@ -303,7 +324,7 @@ dataSeries = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-surface/server/dataFunctions/data_simple_scatter.js b/apps/met-surface/server/dataFunctions/data_simple_scatter.js index 90a2d341d..7f7668887 100644 --- a/apps/met-surface/server/dataFunctions/data_simple_scatter.js +++ b/apps/met-surface/server/dataFunctions/data_simple_scatter.js @@ -12,6 +12,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataSimpleScatter = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -46,13 +47,14 @@ dataSimpleScatter = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); const binParam = curve["bin-parameter"]; const binClause = matsCollections["bin-parameter"].findOne({ name: "bin-parameter", }).optionsMap[binParam]; + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const statisticXSelect = curve.statistic; @@ -94,7 +96,8 @@ dataSimpleScatter = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -128,6 +131,11 @@ dataSimpleScatter = function (plotParams, plotFunction) { const dateRange = matsDataUtils.getDateRange(curve["curve-dates"]); const fromSecs = dateRange.fromSeconds; const toSecs = dateRange.toSeconds; + const { threshold } = curve; + let thresholdClause = ""; + if (threshold !== "All thresholds") { + thresholdClause = `and h.fcst_thresh = '${threshold}'`; + } let vts = ""; // start with an empty string that we can pass to the python script if there aren't vts. let validTimeClause = ""; if (binParam !== "Valid UTC hour") { @@ -214,7 +222,10 @@ dataSimpleScatter = function (plotParams, plotFunction) { descrsClause = `and h.descr IN(${descrs})`; } appParams.aggMethod = curve["aggregation-method"]; - const statType = `met-${statLineType}`; + const statType = + curve["aggregation-method"] === "Overall statistic" && statLineType === "ctc" + ? statLineType + : `met-${statLineType}`; allStatTypes.push(statType); curves[curveIndex].axisXKey = `${variableXStr} ${statisticXSelect}`; // stash the axisKey to use it later for axis options curves[curveIndex].axisYKey = `${variableYStr} ${statisticYSelect}`; // stash the axisKey to use it later for axis options @@ -236,6 +247,7 @@ dataSimpleScatter = function (plotParams, plotFunction) { "{{imClause}} " + "{{scaleClause}} " + "{{variableClause}} " + + "{{thresholdClause}} " + "{{truthClause}} " + "{{validTimeClause}} " + "{{forecastLengthsClause}} " + @@ -252,6 +264,7 @@ dataSimpleScatter = function (plotParams, plotFunction) { statement = statement.replace("{{regionsClause}}", regionsClause); statement = statement.replace("{{imClause}}", imClause); statement = statement.replace("{{scaleClause}}", scaleClause); + statement = statement.replace("{{thresholdClause}}", thresholdClause); statement = statement.replace("{{truthClause}}", truthClause); statement = statement.replace("{{validTimeClause}}", validTimeClause); statement = statement.replace("{{forecastLengthsClause}}", forecastLengthsClause); @@ -288,7 +301,7 @@ dataSimpleScatter = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-airquality/server/dataFunctions/data_threshold.js b/apps/met-surface/server/dataFunctions/data_threshold.js similarity index 87% rename from apps/met-airquality/server/dataFunctions/data_threshold.js rename to apps/met-surface/server/dataFunctions/data_threshold.js index 4b5405ee8..ae1cfa9f8 100644 --- a/apps/met-airquality/server/dataFunctions/data_threshold.js +++ b/apps/met-surface/server/dataFunctions/data_threshold.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataThreshold = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -37,6 +38,7 @@ dataThreshold = function (plotParams, plotFunction) { const allStatTypes = []; const dataset = []; const utcCycleStarts = []; + let axisKey; const axisMap = Object.create(null); let xmax = -1 * Number.MAX_VALUE; let ymax = -1 * Number.MAX_VALUE; @@ -49,9 +51,10 @@ dataThreshold = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -69,6 +72,16 @@ dataThreshold = function (plotParams, plotFunction) { "group_concat(distinct ld.fbar, ';', ld.obar, ';', ld.ffbar, ';', ld.oobar, ';', ld.fobar, ';', " + "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; lineDataType = "line_data_sl1l2"; + } else if (statLineType === "vector") { + statisticClause = + "avg(ld.ufbar) as ufbar, " + + "avg(ld.vfbar) as vfbar, " + + "avg(ld.uobar) as uobar, " + + "avg(ld.vobar) as vobar, " + + "group_concat(distinct ld.ufbar, ';', ld.vfbar, ';', ld.uobar, ';', ld.vobar, ';', " + + "ld.uvfobar, ';', ld.uvffbar, ';', ld.uvoobar, ';', ld.f_speed_bar, ';', ld.o_speed_bar, ';', " + + "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; + lineDataType = "line_data_vl1l2"; } else if (statLineType === "ctc") { statisticClause = "sum(ld.fy_oy) as fy_oy, " + @@ -88,7 +101,13 @@ dataThreshold = function (plotParams, plotFunction) { if (regions.length > 0) { regions = regions .map(function (r) { - return `'${r}'`; + return `'${Object.keys( + matsCollections.region.findOne({ name: "region" }).valuesMap + ).find( + (key) => + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") + )}'`; }) .join(","); regionsClause = `and h.vx_mask IN(${regions})`; @@ -103,13 +122,18 @@ dataThreshold = function (plotParams, plotFunction) { if (im !== "All methods") { imClause = `and h.interp_mthd = '${im}'`; } - const { variable } = curve; + const variable = curve.variable.replace(/___/g, "."); const variableValuesMap = matsCollections.variable.findOne( { name: "variable" }, { valuesMap: 1 } ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; const variableClause = `and h.fcst_var = '${variableValuesMap[variable]}'`; const thresholdClause = "and h.fcst_thresh != 'NA'"; + const { truth } = curve; + let truthClause = ""; + if (truth !== "Any truth dataset") { + truthClause = `and h.obtype = '${truth}'`; + } let vts = ""; // start with an empty string that we can pass to the python script if there aren't vts. let validTimeClause = ""; if ( @@ -199,7 +223,25 @@ dataThreshold = function (plotParams, plotFunction) { // This axisKeySet object is used like a set and if a curve has the same // variable + statistic (axisKey) it will use the same axis. // The axis number is assigned to the axisKeySet value, which is the axisKey. - const axisKey = `${variable} ${statistic}`; + if ( + statistic.includes("vector") && + (statistic.includes("speed") || + statistic.includes("length") || + statistic.includes("Speed") || + statistic.includes("Length")) + ) { + axisKey = "Vector wind speed"; + } else if ( + statistic.includes("vector") && + (statistic.includes("direction") || + statistic.includes("angle") || + statistic.includes("Direction") || + statistic.includes("Angle")) + ) { + axisKey = "Vector wind direction"; + } else { + axisKey = `${variable} ${statistic}`; + } curves[curveIndex].axisKey = axisKey; // stash the axisKey to use it later for axis options if (!diffFrom) { @@ -221,6 +263,7 @@ dataThreshold = function (plotParams, plotFunction) { "{{scaleClause}} " + "{{variableClause}} " + "{{thresholdClause}} " + + "{{truthClause}} " + "{{validTimeClause}} " + "{{forecastLengthsClause}} " + "{{levelsClause}} " + @@ -238,6 +281,7 @@ dataThreshold = function (plotParams, plotFunction) { statement = statement.replace("{{scaleClause}}", scaleClause); statement = statement.replace("{{variableClause}}", variableClause); statement = statement.replace("{{thresholdClause}}", thresholdClause); + statement = statement.replace("{{truthClause}}", truthClause); statement = statement.replace("{{validTimeClause}}", validTimeClause); statement = statement.replace("{{forecastLengthsClause}}", forecastLengthsClause); statement = statement.replace("{{levelsClause}}", levelsClause); @@ -268,7 +312,7 @@ dataThreshold = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-surface/server/dataFunctions/data_validtime.js b/apps/met-surface/server/dataFunctions/data_validtime.js index 640fe9a50..2fb8ef9a8 100644 --- a/apps/met-surface/server/dataFunctions/data_validtime.js +++ b/apps/met-surface/server/dataFunctions/data_validtime.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataValidTime = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -50,9 +51,10 @@ dataValidTime = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -80,6 +82,14 @@ dataValidTime = function (plotParams, plotFunction) { "ld.uvfobar, ';', ld.uvffbar, ';', ld.uvoobar, ';', ld.f_speed_bar, ';', ld.o_speed_bar, ';', " + "ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; lineDataType = "line_data_vl1l2"; + } else if (statLineType === "ctc") { + statisticClause = + "sum(ld.fy_oy) as fy_oy, " + + "sum(ld.fy_on) as fy_on, " + + "sum(ld.fn_oy) as fn_oy, " + + "sum(ld.fn_on) as fn_on, " + + "group_concat(distinct ld.fy_oy, ';', ld.fy_on, ';', ld.fn_oy, ';', ld.fn_on, ';', ld.total, ';', unix_timestamp(ld.fcst_valid_beg), ';', h.fcst_lev order by unix_timestamp(ld.fcst_valid_beg), h.fcst_lev) as sub_data"; + lineDataType = "line_data_ctc"; } const queryTableClause = `from ${database}.stat_header h, ${database}.${lineDataType} ld`; let regions = @@ -95,7 +105,8 @@ dataValidTime = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -117,6 +128,11 @@ dataValidTime = function (plotParams, plotFunction) { { valuesMap: 1 } ).valuesMap[database][curve["data-source"]][selectorPlotType][statLineType]; const variableClause = `and h.fcst_var = '${variableValuesMap[variable]}'`; + const { threshold } = curve; + let thresholdClause = ""; + if (threshold !== "All thresholds") { + thresholdClause = `and h.fcst_thresh = '${threshold}'`; + } const { truth } = curve; let truthClause = ""; if (truth !== "Any truth dataset") { @@ -187,7 +203,10 @@ dataValidTime = function (plotParams, plotFunction) { .join(","); descrsClause = `and h.descr IN(${descrs})`; } - const statType = `met-${statLineType}`; + const statType = + curve["aggregation-method"] === "Overall statistic" && statLineType === "ctc" + ? statLineType + : `met-${statLineType}`; allStatTypes.push(statType); appParams.aggMethod = curve["aggregation-method"]; // axisKey is used to determine which axis a curve should use. @@ -233,6 +252,7 @@ dataValidTime = function (plotParams, plotFunction) { "{{imClause}} " + "{{scaleClause}} " + "{{variableClause}} " + + "{{thresholdClause}} " + "{{truthClause}} " + "{{forecastLengthsClause}} " + "{{levelsClause}} " + @@ -249,6 +269,7 @@ dataValidTime = function (plotParams, plotFunction) { statement = statement.replace("{{imClause}}", imClause); statement = statement.replace("{{scaleClause}}", scaleClause); statement = statement.replace("{{variableClause}}", variableClause); + statement = statement.replace("{{thresholdClause}}", thresholdClause); statement = statement.replace("{{truthClause}}", truthClause); statement = statement.replace("{{forecastLengthsClause}}", forecastLengthsClause); statement = statement.replace("{{levelsClause}}", levelsClause); @@ -279,7 +300,7 @@ dataValidTime = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-surface/server/main.js b/apps/met-surface/server/main.js index 7210f71df..0f7387dda 100644 --- a/apps/met-surface/server/main.js +++ b/apps/met-surface/server/main.js @@ -228,6 +228,7 @@ const doPlotParams = function () { const xOptionsMap = { "Fcst lead time": "select ld.fcst_lead as xVal, ", + Threshold: "select h.fcst_thresh as xVal, ", "Valid UTC hour": "select unix_timestamp(ld.fcst_valid_beg)%(24*3600)/3600 as xVal, ", "Init UTC hour": @@ -244,7 +245,7 @@ const doPlotParams = function () { selected: "", controlButtonCovered: true, unique: false, - default: Object.keys(xOptionsMap)[1], + default: Object.keys(xOptionsMap)[2], controlButtonVisibility: "block", displayOrder: 9, displayPriority: 1, @@ -253,6 +254,7 @@ const doPlotParams = function () { const yOptionsMap = { "Fcst lead time": "ld.fcst_lead as yVal, ", + Threshold: "h.fcst_thresh as yVal, ", "Valid UTC hour": "unix_timestamp(ld.fcst_valid_beg)%(24*3600)/3600 as yVal, ", "Init UTC hour": "unix_timestamp(ld.fcst_init_beg)%(24*3600)/3600 as yVal, ", "Valid Date": "unix_timestamp(ld.fcst_valid_beg) as yVal, ", @@ -314,8 +316,8 @@ const doCurveParams = function () { const masterPlotTypeOptionsMap = { line_data_sl1l2: [ matsTypes.PlotTypes.timeSeries, - matsTypes.PlotTypes.profile, matsTypes.PlotTypes.dieoff, + matsTypes.PlotTypes.threshold, matsTypes.PlotTypes.validtime, matsTypes.PlotTypes.histogram, matsTypes.PlotTypes.contour, @@ -323,8 +325,16 @@ const doCurveParams = function () { ], line_data_vl1l2: [ matsTypes.PlotTypes.timeSeries, - matsTypes.PlotTypes.profile, matsTypes.PlotTypes.dieoff, + matsTypes.PlotTypes.threshold, + matsTypes.PlotTypes.validtime, + matsTypes.PlotTypes.histogram, + matsTypes.PlotTypes.contour, + ], + line_data_ctc: [ + matsTypes.PlotTypes.timeSeries, + matsTypes.PlotTypes.dieoff, + matsTypes.PlotTypes.threshold, matsTypes.PlotTypes.validtime, matsTypes.PlotTypes.histogram, matsTypes.PlotTypes.contour, @@ -366,6 +376,16 @@ const doCurveParams = function () { "Forecast stdev of wind vector length": ["vector"], "Observed stdev of wind vector length": ["vector"], }, + line_data_ctc: { + "CSI (Critical Success Index)": ["ctc"], + "FAR (False Alarm Ratio)": ["ctc"], + "FBIAS (Frequency Bias)": ["ctc"], + "GSS (Gilbert Skill Score)": ["ctc"], + "HSS (Heidke Skill Score)": ["ctc"], + "PODy (Probability of positive detection)": ["ctc"], + "PODn (Probability of negative detection)": ["ctc"], + "POFD (Probability of false detection)": ["ctc"], + }, }; const aggMethodOptionsMap = { @@ -374,6 +394,11 @@ const doCurveParams = function () { "Mean statistic": ["meanStat"], "Median statistic": ["medStat"], }, + ctc: { + "Overall statistic": ["aggStat"], + "Mean statistic": ["meanStat"], + "Median statistic": ["medStat"], + }, vector: { "Overall statistic": ["aggStat"], "Mean statistic": ["meanStat"], @@ -401,6 +426,7 @@ const doCurveParams = function () { const regionModelOptionsMap = {}; const forecastLengthOptionsMap = {}; const levelOptionsMap = {}; + const thresholdOptionsMap = {}; const imOptionsMap = {}; const scaleOptionsMap = {}; const sourceOptionsMap = {}; @@ -412,15 +438,15 @@ const doCurveParams = function () { let dbArr; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select * from surface_database_groups order by db_group;" ); for (let i = 0; i < rows.length; i += 1) { - thisGroup = rows[i].db_group.trim(); + thisGroup = rows[i].db_group.trim().replace(/\./g, "___"); dbs = rows[i].dbs; dbArr = dbs.split(",").map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < dbArr.length; j += 1) { - dbArr[j] = dbArr[j].replace(/'|\[|\]/g, ""); + dbArr[j] = dbArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); } dbGroupMap[thisGroup] = dbArr; } @@ -431,11 +457,11 @@ const doCurveParams = function () { let thisDB; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select distinct db from surface_metexpress_metadata;" ); for (let i = 0; i < rows.length; i += 1) { - thisDB = rows[i].db.trim(); + thisDB = rows[i].db.trim().replace(/\./g, "___"); myDBs.push(thisDB); } } catch (err) { @@ -457,18 +483,19 @@ const doCurveParams = function () { regionModelOptionsMap[thisDB] = {}; forecastLengthOptionsMap[thisDB] = {}; levelOptionsMap[thisDB] = {}; + thresholdOptionsMap[thisDB] = {}; imOptionsMap[thisDB] = {}; scaleOptionsMap[thisDB] = {}; sourceOptionsMap[thisDB] = {}; descrOptionsMap[thisDB] = {}; rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, - `select model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,interp_mthds,gridpoints,truths,mindate,maxdate from surface_metexpress_metadata where db = '${thisDB}' group by model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,interp_mthds,gridpoints,truths,mindate,maxdate order by model,line_data_table,variable;` + sumPool, // eslint-disable-line no-undef + `select model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,trshs,interp_mthds,gridpoints,truths,mindate,maxdate from surface_metexpress_metadata where db = '${thisDB}' group by model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,trshs,interp_mthds,gridpoints,truths,mindate,maxdate order by model,line_data_table,variable;` ); for (let i = 0; i < rows.length; i += 1) { const modelValue = rows[i].model.trim(); - const model = rows[i].display_text.trim(); + const model = rows[i].display_text.trim().replace(/\./g, "___"); modelOptionsMap[thisDB][model] = [modelValue]; const rowMinDate = moment @@ -492,7 +519,7 @@ const doCurveParams = function () { .split(",") .map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < regionsArr.length; j += 1) { - regionsArr[j] = regionsArr[j].replace(/'|\[|\]/g, ""); + regionsArr[j] = regionsArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); if (regionValueKeys.indexOf(regionsArr[j]) !== -1) { regionsArr[j] = regionValuesMap[regionsArr[j]]; } else { @@ -532,6 +559,15 @@ const doCurveParams = function () { } } + const { trshs } = rows[i]; + const trshArr = trshs + .split(",") + .map(Function.prototype.call, String.prototype.trim); + for (let j = 0; j < trshArr.length; j += 1) { + trshArr[j] = trshArr[j].replace(/'|\[|\]/g, ""); + } + trshArr.unshift("All thresholds"); + const ims = rows[i].interp_mthds; const imsArr = ims .split(",") @@ -582,6 +618,10 @@ const doCurveParams = function () { levelOptionsMap[thisDB][model] === undefined ? {} : levelOptionsMap[thisDB][model]; + thresholdOptionsMap[thisDB][model] = + thresholdOptionsMap[thisDB][model] === undefined + ? {} + : thresholdOptionsMap[thisDB][model]; imOptionsMap[thisDB][model] = imOptionsMap[thisDB][model] === undefined ? {} : imOptionsMap[thisDB][model]; scaleOptionsMap[thisDB][model] = @@ -612,6 +652,7 @@ const doCurveParams = function () { regionModelOptionsMap[thisDB][model][thisPlotType] = {}; forecastLengthOptionsMap[thisDB][model][thisPlotType] = {}; levelOptionsMap[thisDB][model][thisPlotType] = {}; + thresholdOptionsMap[thisDB][model][thisPlotType] = {}; imOptionsMap[thisDB][model][thisPlotType] = {}; scaleOptionsMap[thisDB][model][thisPlotType] = {}; sourceOptionsMap[thisDB][model][thisPlotType] = {}; @@ -641,6 +682,7 @@ const doCurveParams = function () { forecastLengthOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = {}; levelOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = {}; + thresholdOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = {}; imOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = {}; scaleOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = {}; sourceOptionsMap[thisDB][model][thisPlotType][thisValidStatType] = {}; @@ -668,6 +710,9 @@ const doCurveParams = function () { levelOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ jsonFriendlyVariable ] = levelsArr; + thresholdOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ + jsonFriendlyVariable + ] = trshArr; imOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ jsonFriendlyVariable ] = imsArr; @@ -709,14 +754,21 @@ const doCurveParams = function () { ], levelsArr ); - imOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ + thresholdOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ jsonFriendlyVariable ] = _.union( - imOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ + thresholdOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ jsonFriendlyVariable ], - imsArr + trshArr ); + imOptionsMap[thisDB][model][thisPlotType][thisValidStatType][variable] = + _.union( + imOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ + jsonFriendlyVariable + ], + imsArr + ); scaleOptionsMap[thisDB][model][thisPlotType][thisValidStatType][ jsonFriendlyVariable ] = _.union( @@ -1109,6 +1161,7 @@ const doCurveParams = function () { "region", "forecast-length", "level", + "threshold", "interp-method", "scale", "truth", @@ -1187,6 +1240,71 @@ const doCurveParams = function () { } } + if (matsCollections.threshold.findOne({ name: "threshold" }) === undefined) { + matsCollections.threshold.insert({ + name: "threshold", + type: matsTypes.InputTypes.select, + optionsMap: thresholdOptionsMap, + options: + thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ + Object.keys( + thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ + defaultStatType + ] + )[0] + ], + superiorNames: ["database", "data-source", "plot-type", "statistic", "variable"], + controlButtonCovered: true, + unique: false, + default: + thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][defaultStatType][ + Object.keys( + thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ + defaultStatType + ] + )[0] + ][0], + controlButtonVisibility: "block", + displayOrder: 1, + displayPriority: 1, + displayGroup: 4, + }); + } else { + // it is defined but check for necessary update + const currentParam = matsCollections.threshold.findOne({ name: "threshold" }); + if (!matsDataUtils.areObjectsEqual(thresholdOptionsMap, currentParam.optionsMap)) { + // have to reload threshold data + matsCollections.threshold.update( + { name: "threshold" }, + { + $set: { + optionsMap: thresholdOptionsMap, + options: + thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ + defaultStatType + ][ + Object.keys( + thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ + defaultStatType + ] + )[0] + ], + default: + thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ + defaultStatType + ][ + Object.keys( + thresholdOptionsMap[defaultDB][defaultModel][defaultPlotType][ + defaultStatType + ] + )[0] + ][0], + }, + } + ); + } + } + if ( matsCollections["interp-method"].findOne({ name: "interp-method" }) === undefined ) { @@ -1336,9 +1454,9 @@ const doCurveParams = function () { unique: false, default: sourceDefault, controlButtonVisibility: "block", - displayOrder: 4, + displayOrder: 5, displayPriority: 1, - displayGroup: 4, + displayGroup: 5, }); } else { // it is defined but check for necessary update @@ -1868,6 +1986,7 @@ const doCurveTextPatterns = function () { ["", "database", "."], ["", "data-source", " in "], ["", "region", ", "], + ["", "threshold", ", "], ["", "interp-method", " "], ["", "scale", ", "], ["", "variable", " "], @@ -1888,6 +2007,7 @@ const doCurveTextPatterns = function () { "region", "statistic", "variable", + "threshold", "interp-method", "scale", "valid-time", @@ -1907,6 +2027,7 @@ const doCurveTextPatterns = function () { ["", "database", "."], ["", "data-source", " in "], ["", "region", ", "], + ["", "threshold", ", "], ["", "interp-method", " "], ["", "scale", ", "], ["", "variable", " "], @@ -1928,6 +2049,7 @@ const doCurveTextPatterns = function () { "region", "statistic", "variable", + "threshold", "interp-method", "scale", "dieoff-type", @@ -1941,6 +2063,45 @@ const doCurveTextPatterns = function () { ], groupSize: 6, }); + matsCollections.CurveTextPatterns.insert({ + plotType: matsTypes.PlotTypes.threshold, + textPattern: [ + ["", "label", ": "], + ["", "database", "."], + ["", "data-source", " in "], + ["", "region", ", "], + ["", "interp-method", " "], + ["", "scale", ", "], + ["", "variable", " "], + ["", "statistic", " "], + ["", "aggregation-method", ", "], + ["level: ", "level", ", "], + ["fcst_len: ", "forecast-length", "h, "], + ["valid-time: ", "valid-time", ", "], + ["", "truth", ", "], + ["desc: ", "description", ", "], + ["", "curve-dates", ""], + ], + displayParams: [ + "label", + "group", + "database", + "data-source", + "region", + "statistic", + "variable", + "interp-method", + "scale", + "forecast-length", + "valid-time", + "level", + "truth", + "description", + "aggregation-method", + "curve-dates", + ], + groupSize: 6, + }); matsCollections.CurveTextPatterns.insert({ plotType: matsTypes.PlotTypes.validtime, textPattern: [ @@ -1948,6 +2109,7 @@ const doCurveTextPatterns = function () { ["", "database", "."], ["", "data-source", " in "], ["", "region", ", "], + ["", "threshold", ", "], ["", "interp-method", " "], ["", "scale", ", "], ["", "variable", " "], @@ -1967,6 +2129,7 @@ const doCurveTextPatterns = function () { "region", "statistic", "variable", + "threshold", "interp-method", "scale", "forecast-length", @@ -1985,6 +2148,7 @@ const doCurveTextPatterns = function () { ["", "database", "."], ["", "data-source", " in "], ["", "region", ", "], + ["", "threshold", ", "], ["", "interp-method", " "], ["", "scale", ", "], ["", "variable", " "], @@ -2004,6 +2168,7 @@ const doCurveTextPatterns = function () { "region", "statistic", "variable", + "threshold", "interp-method", "scale", "valid-time", @@ -2022,6 +2187,7 @@ const doCurveTextPatterns = function () { ["", "database", "."], ["", "data-source", " in "], ["", "region", ", "], + ["", "threshold", ", "], ["", "interp-method", " "], ["", "scale", ", "], ["", "variable", " "], @@ -2041,6 +2207,7 @@ const doCurveTextPatterns = function () { "region", "statistic", "variable", + "threshold", "interp-method", "scale", "valid-time", @@ -2059,6 +2226,7 @@ const doCurveTextPatterns = function () { ["", "database", "."], ["", "data-source", " in "], ["", "region", ", "], + ["", "threshold", ", "], ["", "interp-method", " "], ["", "scale", ", "], ["", "variable", " "], @@ -2082,6 +2250,7 @@ const doCurveTextPatterns = function () { "variable", "y-statistic", "y-variable", + "threshold", "interp-method", "scale", "valid-time", @@ -2132,6 +2301,12 @@ const doPlotGraph = function () { dataFunction: "dataDieoff", checked: false, }); + matsCollections.PlotGraphFunctions.insert({ + plotType: matsTypes.PlotTypes.threshold, + graphFunction: "graphPlotly", + dataFunction: "dataThreshold", + checked: false, + }); matsCollections.PlotGraphFunctions.insert({ plotType: matsTypes.PlotTypes.validtime, graphFunction: "graphPlotly", @@ -2162,6 +2337,7 @@ const doPlotGraph = function () { Meteor.startup(function () { matsCollections.Databases.remove({}); if (matsCollections.Databases.find({}).count() < 0) { + // eslint-disable-next-line no-console console.warn( "main startup: corrupted Databases collection: dropping Databases collection" ); @@ -2200,6 +2376,7 @@ Meteor.startup(function () { ); // the pool is intended to be global if (sumSettings) { + // eslint-disable-next-line no-undef sumPool = mysql.createPool(sumSettings); allPools.push({ pool: "sumPool", role: matsTypes.DatabaseRoles.SUMS_DATA }); } @@ -2224,6 +2401,7 @@ Meteor.startup(function () { // These are application specific mongo data - like curve params // The appSpecificResetRoutines object is a special name, // as is doCurveParams. The refreshMetaData mechanism depends on them being named that way. +// eslint-disable-next-line no-undef appSpecificResetRoutines = [ doPlotGraph, doCurveParams, diff --git a/apps/met-upperair/.eslintrc.json b/apps/met-upperair/.eslintrc.json index a33ac158f..79d49c5bb 100644 --- a/apps/met-upperair/.eslintrc.json +++ b/apps/met-upperair/.eslintrc.json @@ -28,13 +28,6 @@ "space-before-function-paren": "off", // for Meteor API's that rely on `this` context, e.g. Template.onCreated and publications "func-names": "off", - "prefer-arrow-callback": "off", - - // Vx Team modifications - Warn on rules that would require refactoring to implement. - // We want to be able to turn these back into "error"'s at some point. However, for - // our first pass, we'll only consider the checks that ESLint can auto-fix as errors. - // https://eslint.org/docs/latest/use/configure/rules#rule-severities - "no-undef": "warn", - "no-unused-vars": "warn" + "prefer-arrow-callback": "off" } } diff --git a/apps/met-upperair/client/main.js b/apps/met-upperair/client/main.js index a87407a1f..ecd922b6a 100644 --- a/apps/met-upperair/client/main.js +++ b/apps/met-upperair/client/main.js @@ -2,6 +2,7 @@ * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. */ +// eslint-disable-next-line no-unused-vars import { matsTypes, matsCollections, methods } from "meteor/randyp:mats-common"; import "@fortawesome/fontawesome-free"; import "@fortawesome/fontawesome-free/css/all.css"; diff --git a/apps/met-upperair/server/dataFunctions/data_contour.js b/apps/met-upperair/server/dataFunctions/data_contour.js index 71e523d59..72604ecff 100644 --- a/apps/met-upperair/server/dataFunctions/data_contour.js +++ b/apps/met-upperair/server/dataFunctions/data_contour.js @@ -12,6 +12,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataContour = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -46,9 +47,10 @@ dataContour = function (plotParams, plotFunction) { // initialize variables specific to the curve const curve = curves[0]; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -93,7 +95,8 @@ dataContour = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -301,7 +304,7 @@ dataContour = function (plotParams, plotFunction) { let finishMoment; try { // send the query statement to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-upperair/server/dataFunctions/data_dieoff.js b/apps/met-upperair/server/dataFunctions/data_dieoff.js index 0a25bd146..fa1839c17 100644 --- a/apps/met-upperair/server/dataFunctions/data_dieoff.js +++ b/apps/met-upperair/server/dataFunctions/data_dieoff.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataDieoff = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -50,9 +51,10 @@ dataDieoff = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -95,7 +97,8 @@ dataDieoff = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -299,7 +302,7 @@ dataDieoff = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-upperair/server/dataFunctions/data_histogram.js b/apps/met-upperair/server/dataFunctions/data_histogram.js index 78683a7da..f28653d8c 100644 --- a/apps/met-upperair/server/dataFunctions/data_histogram.js +++ b/apps/met-upperair/server/dataFunctions/data_histogram.js @@ -11,6 +11,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataHistogram = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -51,9 +52,10 @@ dataHistogram = function (plotParams, plotFunction) { const { diffFrom } = curve; dataFoundForCurve[curveIndex] = true; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -96,7 +98,8 @@ dataHistogram = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -282,7 +285,7 @@ dataHistogram = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-upperair/server/dataFunctions/data_profile.js b/apps/met-upperair/server/dataFunctions/data_profile.js index 14c9dea09..debeab82b 100644 --- a/apps/met-upperair/server/dataFunctions/data_profile.js +++ b/apps/met-upperair/server/dataFunctions/data_profile.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataProfile = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -49,9 +50,10 @@ dataProfile = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -94,7 +96,8 @@ dataProfile = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -278,7 +281,7 @@ dataProfile = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-upperair/server/dataFunctions/data_series.js b/apps/met-upperair/server/dataFunctions/data_series.js index 87d68d018..3b38ee69d 100644 --- a/apps/met-upperair/server/dataFunctions/data_series.js +++ b/apps/met-upperair/server/dataFunctions/data_series.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataSeries = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -53,9 +54,10 @@ dataSeries = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -98,7 +100,8 @@ dataSeries = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -303,7 +306,7 @@ dataSeries = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-upperair/server/dataFunctions/data_simple_scatter.js b/apps/met-upperair/server/dataFunctions/data_simple_scatter.js index 90a2d341d..929486705 100644 --- a/apps/met-upperair/server/dataFunctions/data_simple_scatter.js +++ b/apps/met-upperair/server/dataFunctions/data_simple_scatter.js @@ -12,6 +12,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataSimpleScatter = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -46,13 +47,14 @@ dataSimpleScatter = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); const binParam = curve["bin-parameter"]; const binClause = matsCollections["bin-parameter"].findOne({ name: "bin-parameter", }).optionsMap[binParam]; + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const statisticXSelect = curve.statistic; @@ -94,7 +96,8 @@ dataSimpleScatter = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -288,7 +291,7 @@ dataSimpleScatter = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-upperair/server/dataFunctions/data_validtime.js b/apps/met-upperair/server/dataFunctions/data_validtime.js index 640fe9a50..594d9f195 100644 --- a/apps/met-upperair/server/dataFunctions/data_validtime.js +++ b/apps/met-upperair/server/dataFunctions/data_validtime.js @@ -13,6 +13,7 @@ import { } from "meteor/randyp:mats-common"; import { moment } from "meteor/momentjs:moment"; +// eslint-disable-next-line no-undef dataValidTime = function (plotParams, plotFunction) { // initialize variables common to all curves const appParams = { @@ -50,9 +51,10 @@ dataValidTime = function (plotParams, plotFunction) { const curve = curves[curveIndex]; const { diffFrom } = curve; const { label } = curve; - const { database } = curve; + const database = curve.database.replace(/___/g, "."); + const modelDisplay = curve["data-source"].replace(/___/g, "."); const model = matsCollections["data-source"].findOne({ name: "data-source" }) - .optionsMap[database][curve["data-source"]][0]; + .optionsMap[database][modelDisplay][0]; const modelClause = `and h.model = '${model}'`; const selectorPlotType = curve["plot-type"]; const { statistic } = curve; @@ -95,7 +97,8 @@ dataValidTime = function (plotParams, plotFunction) { matsCollections.region.findOne({ name: "region" }).valuesMap ).find( (key) => - matsCollections.region.findOne({ name: "region" }).valuesMap[key] === r + matsCollections.region.findOne({ name: "region" }).valuesMap[key] === + r.replace(/___/g, ".") )}'`; }) .join(","); @@ -279,7 +282,7 @@ dataValidTime = function (plotParams, plotFunction) { let finishMoment; try { // send the query statements to the query function - queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); + queryResult = matsDataQueryUtils.queryDBPython(sumPool, queryArray); // eslint-disable-line no-undef finishMoment = moment(); dataRequests["data retrieval (query) time"] = { begin: startMoment.format(), diff --git a/apps/met-upperair/server/main.js b/apps/met-upperair/server/main.js index d278d446e..fbb7fe6c5 100644 --- a/apps/met-upperair/server/main.js +++ b/apps/met-upperair/server/main.js @@ -414,15 +414,15 @@ const doCurveParams = function () { let dbArr; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select * from upperair_database_groups order by db_group;" ); for (let i = 0; i < rows.length; i += 1) { - thisGroup = rows[i].db_group.trim(); + thisGroup = rows[i].db_group.trim().replace(/\./g, "___"); dbs = rows[i].dbs; dbArr = dbs.split(",").map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < dbArr.length; j += 1) { - dbArr[j] = dbArr[j].replace(/'|\[|\]/g, ""); + dbArr[j] = dbArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); } dbGroupMap[thisGroup] = dbArr; } @@ -433,11 +433,11 @@ const doCurveParams = function () { let thisDB; try { rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef "select distinct db from upperair_metexpress_metadata;" ); for (let i = 0; i < rows.length; i += 1) { - thisDB = rows[i].db.trim(); + thisDB = rows[i].db.trim().replace(/\./g, "___"); myDBs.push(thisDB); } } catch (err) { @@ -465,12 +465,12 @@ const doCurveParams = function () { descrOptionsMap[thisDB] = {}; rows = matsDataQueryUtils.simplePoolQueryWrapSynchronous( - sumPool, + sumPool, // eslint-disable-line no-undef `select model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,interp_mthds,gridpoints,truths,mindate,maxdate from upperair_metexpress_metadata where db = '${thisDB}' group by model,display_text,line_data_table,variable,regions,levels,descrs,fcst_orig,interp_mthds,gridpoints,truths,mindate,maxdate order by model,line_data_table,variable;` ); for (let i = 0; i < rows.length; i += 1) { const modelValue = rows[i].model.trim(); - const model = rows[i].display_text.trim(); + const model = rows[i].display_text.trim().replace(/\./g, "___"); modelOptionsMap[thisDB][model] = [modelValue]; const rowMinDate = moment @@ -494,7 +494,7 @@ const doCurveParams = function () { .split(",") .map(Function.prototype.call, String.prototype.trim); for (let j = 0; j < regionsArr.length; j += 1) { - regionsArr[j] = regionsArr[j].replace(/'|\[|\]/g, ""); + regionsArr[j] = regionsArr[j].replace(/'|\[|\]/g, "").replace(/\./g, "___"); if (regionValueKeys.indexOf(regionsArr[j]) !== -1) { regionsArr[j] = regionValuesMap[regionsArr[j]]; } else { @@ -2207,6 +2207,7 @@ const doPlotGraph = function () { Meteor.startup(function () { matsCollections.Databases.remove({}); if (matsCollections.Databases.find({}).count() < 0) { + // eslint-disable-next-line no-console console.warn( "main startup: corrupted Databases collection: dropping Databases collection" ); @@ -2245,6 +2246,7 @@ Meteor.startup(function () { ); // the pool is intended to be global if (sumSettings) { + // eslint-disable-next-line no-undef sumPool = mysql.createPool(sumSettings); allPools.push({ pool: "sumPool", role: matsTypes.DatabaseRoles.SUMS_DATA }); } @@ -2269,6 +2271,7 @@ Meteor.startup(function () { // These are application specific mongo data - like curve params // The appSpecificResetRoutines object is a special name, // as is doCurveParams. The refreshMetaData mechanism depends on them being named that way. +// eslint-disable-next-line no-undef appSpecificResetRoutines = [ doPlotGraph, doCurveParams, diff --git a/scripts/matsMetaDataForApps/createMetaData/mysql/metexpress/MEairquality.py b/scripts/matsMetaDataForApps/createMetaData/mysql/metexpress/MEairquality.py deleted file mode 100755 index f0964a6af..000000000 --- a/scripts/matsMetaDataForApps/createMetaData/mysql/metexpress/MEairquality.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python3 -""" -This script creates the metadata tables required for a METexpress air quality app. It parses the required fields from any -databases that begin with 'mv_' in a mysql instance. - -Usage: ["(c)nf_file=", "[(m)ats_metadata_database_name]", - "[(D)ata_table_stat_header_id_limit - default is 10,000,000,000]", - "[(d)atabase name]" "(u)=metexpress_base_url"] - cnf_file = None - -Author: Molly B Smith, heavily modified by Randy Pierce -""" - -# Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. - - -import sys -from datetime import datetime - -from metexpress.MEmetadata import ParentMetadata - - -class MEAirquality(ParentMetadata): - def __init__(self, options): - options['name'] = __name__ - options['appSpecificWhereClause'] = 'fcst_var regexp "^OZ|^PM25|^PMTF|^PDM|^PMAVE"' - options['statHeaderType'] = 'stat_header' - options['line_data_table'] = ["line_data_sl1l2", # used for scalar stats on all plot types - "line_data_ctc"] # used for ctc stats on all plot types - options['metadata_table'] = "airquality_metexpress_metadata" - options['app_reference'] = "met-airquality" - options['database_groups'] = "airquality_database_groups" - super().__init__(options) - - @staticmethod - def get_app_reference(): - return "met-airquality" - - def strip_level(self, elem): - # helper function for sorting levels - if elem[0] in ['Z', 'H', 'L', 'A']: - try: - return int(elem[1:]) - except ValueError: - return 0 - else: - try: - return int(float(elem) + 10000) - except ValueError: - return 0 - - def strip_trsh(self, elem): - # helper function for sorting thresholds - if elem[0] == '>': - try: - return 1000 + int(float(elem[1:])) * 10000 - except ValueError: - try: - return 1000.0001 + int(float(elem[2:])) * 10000 - except ValueError: - return 3000 - elif elem[0] == '<': - try: - return 4000 + int(float(elem[1:])) * 10000 - except ValueError: - try: - return 4000.0001 + int(float(elem[2:])) * 10000 - except ValueError: - return 6000 - elif elem[0] == '=': - try: - return 7000 + int(float(elem[1:])) * 10000 - except ValueError: - try: - return 70000.0001 + int(float(elem[2:])) * 10000 - except ValueError: - return 90000 - else: - try: - return int(float(elem)) - except ValueError: - return 0 - - -if __name__ == '__main__': - options = MEAirquality.get_options(sys.argv) - start = str(datetime.now()) - print('AIR QUALITY METEXPRESS METADATA START: ' + start) - me_dbcreator = MEAirquality(options) - me_dbcreator.main() - print('AIR QUALITY METEXPRESS METADATA END: ' + str(datetime.now()) + " started at: " + start) - sys.exit(0) \ No newline at end of file diff --git a/scripts/matsMetaDataForApps/createMetaData/mysql/metexpress/MEmetadata.py b/scripts/matsMetaDataForApps/createMetaData/mysql/metexpress/MEmetadata.py index faaf55812..e2361d4f8 100755 --- a/scripts/matsMetaDataForApps/createMetaData/mysql/metexpress/MEmetadata.py +++ b/scripts/matsMetaDataForApps/createMetaData/mysql/metexpress/MEmetadata.py @@ -540,7 +540,7 @@ def build_stats_object(self): app_specific_clause = end_query[:-1] # select the minimum length set of stat_header_ids from the line_data_table that are unique - # with respect to model, variable, and vx_mask. + # with respect to model, variable, and level. # these will be used to qualify the distinct set of fcst_leads from the line data table. get_stat_header_ids = "select stat_header_id from " + \ "(select group_concat(stat_header_id) as stat_header_id " + \ @@ -550,7 +550,7 @@ def build_stats_object(self): "' and fcst_var = '" + fvar + \ "' order by stat_header_id)" + \ app_specific_clause + \ - " group by model, fcst_var, vx_mask) as stat_header_id order by length(stat_header_id) limit 1;" + " group by model, fcst_var, fcst_lev) as stat_header_id order by length(stat_header_id) limit 1;" if debug: print(self.script_name + " - Getting get_stat_header_ids lens for model " + model + " and variable " + fvar + " sql: " + get_stat_header_ids) try: diff --git a/scripts/matsMetaDataForApps/createMetaData/mysql/metexpress/MEsurface.py b/scripts/matsMetaDataForApps/createMetaData/mysql/metexpress/MEsurface.py index 91a7b9c8a..34baf1372 100755 --- a/scripts/matsMetaDataForApps/createMetaData/mysql/metexpress/MEsurface.py +++ b/scripts/matsMetaDataForApps/createMetaData/mysql/metexpress/MEsurface.py @@ -23,10 +23,11 @@ class MESurface(ParentMetadata): def __init__(self, options): options['name'] = __name__ - options['appSpecificWhereClause'] = 'fcst_lev in ("MSL", "SFC", "SFC=", "Z0", "Z2", "Z10", "H0", "H2", "H10", "L0") and fcst_var not regexp "^OZ|^PM25|^PMTF|^PDM|^PMAVE"' + options['appSpecificWhereClause'] = 'fcst_lev in ("MSL", "SFC", "SFC=", "Z0", "Z2", "Z10", "H0", "H2", "H10", "L0")' options['statHeaderType'] = 'stat_header' options['line_data_table'] = ["line_data_sl1l2", # used for scalar stats on all plot types - "line_data_vl1l2"] # used for vector stats on all plot types + "line_data_vl1l2", # used for vector stats on all plot types + "line_data_ctc"] # used for ctc stats on all plot types options['metadata_table'] = "surface_metexpress_metadata" options['app_reference'] = "met-surface" options['database_groups'] = "surface_database_groups" diff --git a/tests/src/features/met-airquality/basic/addRemoveContour.feature b/tests/src/features/met-airquality/basic/addRemoveContour.feature deleted file mode 100644 index de1c693c4..000000000 --- a/tests/src/features/met-airquality/basic/addRemoveContour.feature +++ /dev/null @@ -1,42 +0,0 @@ -Feature: Add Remove Contour - - As an unauthenticated user to the app, - with the app in its default state, - I want click the contour radio button, - I want to add one curve. - then plot that curve and see the graph, - then go back to the curve management page, - then delete that curve. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: addRemoveContour - When I set the plot type to "Contour" - Then the plot type should be "Contour" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I set the dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - Then I click the "Add Curve" button - Then "Curve0" is added - And I should see a list of curves containing "Curve0" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Contour" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - Then I click the "Remove Curve0" button - And the "Remove curve Curve0" button should be visible - Then I click the "Remove curve Curve0" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/addRemoveCurve.feature b/tests/src/features/met-airquality/basic/addRemoveCurve.feature deleted file mode 100644 index 1d38d7d2c..000000000 --- a/tests/src/features/met-airquality/basic/addRemoveCurve.feature +++ /dev/null @@ -1,41 +0,0 @@ -Feature: Add Remove Curve - - As an unauthenticated user to the app, - with the app in its default state, - I want to add one curve - then plot that curve and see the graph, - then go back to the curve management page, - then delete that curve. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: addRemoveCurve - When I set the plot type to "TimeSeries" - Then the plot type should be "TimeSeries" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I set the dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - Then I click the "Add Curve" button - Then "Curve0" is added - And I should see a list of curves containing "Curve0" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Time Series" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - Then I click the "Remove Curve0" button - And the "Remove curve Curve0" button should be visible - Then I click the "Remove curve Curve0" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/addRemoveDieOffCurve.feature b/tests/src/features/met-airquality/basic/addRemoveDieOffCurve.feature deleted file mode 100644 index d3163a36a..000000000 --- a/tests/src/features/met-airquality/basic/addRemoveDieOffCurve.feature +++ /dev/null @@ -1,43 +0,0 @@ -Feature: Add Remove Dieoff Curve - - As an unauthenticated user to the app, - with the app in its default state, - I want click the dieoff radio button, - I want to set the forecast-length selector to dieoff - I want to add one curve - then plot that curve and see the graph, - then go back to the curve management page, - then delete that curve. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: addRemoveDieoffCurve - When I set the plot type to "Dieoff" - Then the plot type should be "Dieoff" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I set the curve-dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the curve-dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - Then I click the "Add Curve" button - Then "Curve0" is added - And I should see a list of curves containing "Curve0" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Dieoff" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - Then I click the "Remove Curve0" button - And the "Remove curve Curve0" button should be visible - Then I click the "Remove curve Curve0" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/addRemoveHistogram.feature b/tests/src/features/met-airquality/basic/addRemoveHistogram.feature deleted file mode 100644 index 3b0b0fdb1..000000000 --- a/tests/src/features/met-airquality/basic/addRemoveHistogram.feature +++ /dev/null @@ -1,42 +0,0 @@ -Feature: Add Remove Histogram - - As an unauthenticated user to the app, - with the app in its default state, - I want click the histogram radio button, - I want to add one curve - then plot that curve and see the graph, - then go back to the curve management page, - then delete that curve. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: addRemoveHistogram - When I set the plot type to "Histogram" - Then the plot type should be "Histogram" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I set the curve-dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the curve-dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - Then I click the "Add Curve" button - Then "Curve0" is added - And I should see a list of curves containing "Curve0" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Histogram" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - Then I click the "Remove Curve0" button - And the "Remove curve Curve0" button should be visible - Then I click the "Remove curve Curve0" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/addRemoveScatter.feature b/tests/src/features/met-airquality/basic/addRemoveScatter.feature deleted file mode 100644 index 1f41e0909..000000000 --- a/tests/src/features/met-airquality/basic/addRemoveScatter.feature +++ /dev/null @@ -1,49 +0,0 @@ -Feature: Add Remove Scatter - - As an unauthenticated user to the app, - with the app in its default state, - I want to add one curve - then plot that curve and see the graph, - then go back to the curve management page, - then delete that curve. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: addRemoveScatter - When I set the plot type to "SimpleScatter" - Then the plot type should be "SimpleScatter" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I change the "statistic" parameter to "RMSE" - Then the "statistic" parameter value matches "RMSE" - When I change the "variable" parameter to "OZMX/8" - Then the "variable" parameter value matches "OZMX/8" - When I change the "y-statistic" parameter to "RMSE" - Then the "y-statistic" parameter value matches "RMSE" - When I change the "y-variable" parameter to "OZMX/1" - Then the "y-variable" parameter value matches "OZMX/1" - When I set the curve-dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the curve-dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - Then I click the "Add Curve" button - Then "Curve0" is added - And I should see a list of curves containing "Curve0" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Simple Scatter" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - Then I click the "Remove Curve0" button - And the "Remove curve Curve0" button should be visible - Then I click the "Remove curve Curve0" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/addRemoveTwoScatters.feature b/tests/src/features/met-airquality/basic/addRemoveTwoScatters.feature deleted file mode 100644 index afa3d849b..000000000 --- a/tests/src/features/met-airquality/basic/addRemoveTwoScatters.feature +++ /dev/null @@ -1,65 +0,0 @@ -Feature: Add Remove Two Scatters - - As an unauthenticated user to the app, - with the app in its default state, - I want to add one curve - I want to change the data-source to HRRR_GSL - I want to add one other curve - then plot unmatched and see the graph, - then go back to the curve management page, - then remove all curves. - I should have no curves. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: addRemoveTwoScatters - When I set the plot type to "SimpleScatter" - Then the plot type should be "SimpleScatter" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I change the "statistic" parameter to "RMSE" - Then the "statistic" parameter value matches "RMSE" - When I change the "variable" parameter to "OZMX/8" - Then the "variable" parameter value matches "OZMX/8" - When I change the "y-statistic" parameter to "RMSE" - Then the "y-statistic" parameter value matches "RMSE" - When I change the "y-variable" parameter to "OZMX/1" - Then the "y-variable" parameter value matches "OZMX/1" - When I set the curve-dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the curve-dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - Then I click the "Add Curve" button - Then "Curve0" is added - - When I change the "data-source" parameter to "CMAQPARA11/148" - Then the "data-source" parameter value matches "CMAQPARA11/148" - When I click the "Add Curve" button - Then "Curve1" is added - And I should see a list of curves containing "Curve0,Curve1" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Simple Scatter" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Simple Scatter" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "Remove All" button - And the "Remove all the curves" button should be visible - Then I click the "Remove all the curves" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/addRemoveValidTimeCurve.feature b/tests/src/features/met-airquality/basic/addRemoveValidTimeCurve.feature deleted file mode 100644 index 07666d780..000000000 --- a/tests/src/features/met-airquality/basic/addRemoveValidTimeCurve.feature +++ /dev/null @@ -1,42 +0,0 @@ -Feature: Add Remove Valid Time Curve - - As an unauthenticated user to the app, - with the app in its default state, - I want click the validtime radio button, - I want to add one curve - then plot that curve and see the graph, - then go back to the curve management page, - then delete that curve. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: addRemoveValidTimeCurve - When I set the plot type to "ValidTime" - Then the plot type should be "ValidTime" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I set the curve-dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the curve-dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - Then I click the "Add Curve" button - Then "Curve0" is added - And I should see a list of curves containing "Curve0" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Valid Time" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - Then I click the "Remove Curve0" button - And the "Remove curve Curve0" button should be visible - Then I click the "Remove curve Curve0" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesDieoff.feature b/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesDieoff.feature deleted file mode 100644 index 0a8a15695..000000000 --- a/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesDieoff.feature +++ /dev/null @@ -1,101 +0,0 @@ -Feature: Match Unmatch Diff Curves Dieoff - - As an unauthenticated user to the app, - with the app in its default state so that the plots are Dieoff, - I want to add two curves, plot unmatched, and then return to the main page. - I then want to add a matched difference curve, plot unmatched, return to the main page, plot matched, and then return to the main page. - I then want to add a piecewise difference curve, plot unmatched, return to the main page, plot matched, and then return to the main page. - I want to end by removing all of the curves. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: matchUnmatchDiffCurvesDieoff - When I set the plot type to "Dieoff" - Then the plot type should be "Dieoff" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I set the curve-dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the curve-dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - When I change the "dieoff-type" parameter to "Dieoff for a specified UTC cycle init hour" - Then the "dieoff-type" parameter value matches "Dieoff for a specified UTC cycle init hour" - When I click the "Add Curve" button - Then "Curve0" is added - - When I change the "data-source" parameter to "CMAQPARA11/148" - Then the "data-source" parameter value matches "CMAQPARA11/148" - When I click the "Add Curve" button - Then "Curve1" is added - And I should see a list of curves containing "Curve0,Curve1" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Dieoff" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Dieoff" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "matching diffs" radio button - Then "Curve1-Curve0" is added - And I should see a list of curves containing "Curve0,Curve1,Curve1-Curve0" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Dieoff" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Dieoff" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "pairwise diffs" radio button - Then the plot format should be "pairwise" - Then I should see a list of curves containing "Curve0,Curve1,Curve1-Curve0" - And I should have 3 curves - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Dieoff" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Dieoff" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "no diffs" radio button - Then I should see a list of curves containing "Curve0,Curve1" - And I should have 2 curves - - When I click the "Remove All" button - And the "Remove all the curves" button should be visible - Then I click the "Remove all the curves" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesHistogram.feature b/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesHistogram.feature deleted file mode 100644 index a6123790b..000000000 --- a/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesHistogram.feature +++ /dev/null @@ -1,99 +0,0 @@ -Feature: Match Unmatch Diff Curves Histogram - - As an unauthenticated user to the app, - with the app in its default state so that the plots are Histogram, - I want to add two curves, plot unmatched, and then return to the main page. - I then want to add a matched difference curve, plot unmatched, return to the main page, plot matched, and then return to the main page. - I then want to add a piecewise difference curve, plot unmatched, return to the main page, plot matched, and then return to the main page. - I want to end by removing all of the curves. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: matchUnmatchDiffCurvesHistogram - When I set the plot type to "Histogram" - Then the plot type should be "Histogram" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I set the curve-dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the curve-dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - When I click the "Add Curve" button - Then "Curve0" is added - - When I change the "data-source" parameter to "CMAQPARA11/148" - Then the "data-source" parameter value matches "CMAQPARA11/148" - When I click the "Add Curve" button - Then "Curve1" is added - And I should see a list of curves containing "Curve0,Curve1" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Histogram" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Histogram" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "matching diffs" radio button - Then "Curve1-Curve0" is added - And I should see a list of curves containing "Curve0,Curve1,Curve1-Curve0" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Histogram" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Histogram" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "pairwise diffs" radio button - Then the plot format should be "pairwise" - Then I should see a list of curves containing "Curve0,Curve1,Curve1-Curve0" - And I should have 3 curves - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Histogram" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Histogram" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "no diffs" radio button - Then I should see a list of curves containing "Curve0,Curve1" - And I should have 2 curves - - When I click the "Remove All" button - And the "Remove all the curves" button should be visible - Then I click the "Remove all the curves" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesTimeseries.feature b/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesTimeseries.feature deleted file mode 100644 index 412f99c63..000000000 --- a/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesTimeseries.feature +++ /dev/null @@ -1,99 +0,0 @@ -Feature: Match Unmatch Diff Curves Timeseries - - As an unauthenticated user to the app, - with the app in its default state so that the plots are time series, - I want to add two curves, plot unmatched, and then return to the main page. - I then want to add a matched difference curve, plot unmatched, return to the main page, plot matched, and then return to the main page. - I then want to add a piecewise difference curve, plot unmatched, return to the main page, plot matched, and then return to the main page. - I want to end by removing all of the curves. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: matchUnmatchDiffCurvesTimeseries - When I set the plot type to "TimeSeries" - Then the plot type should be "TimeSeries" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I set the dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - When I click the "Add Curve" button - Then "Curve0" is added - - When I change the "data-source" parameter to "CMAQPARA11/148" - Then the "data-source" parameter value matches "CMAQPARA11/148" - When I click the "Add Curve" button - Then "Curve1" is added - And I should see a list of curves containing "Curve0,Curve1" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Time Series" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Time Series" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "matching diffs" radio button - Then "Curve1-Curve0" is added - And I should see a list of curves containing "Curve0,Curve1,Curve1-Curve0" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Time Series" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Time Series" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "pairwise diffs" radio button - Then the plot format should be "pairwise" - Then I should see a list of curves containing "Curve0,Curve1,Curve1-Curve0" - And I should have 3 curves - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Time Series" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Time Series" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "no diffs" radio button - Then I should see a list of curves containing "Curve0,Curve1" - And I should have 2 curves - - When I click the "Remove All" button - And the "Remove all the curves" button should be visible - Then I click the "Remove all the curves" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesValidTime.feature b/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesValidTime.feature deleted file mode 100644 index 508ca3ea3..000000000 --- a/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesValidTime.feature +++ /dev/null @@ -1,99 +0,0 @@ -Feature: Match Unmatch Diff Curves Valid Time - - As an unauthenticated user to the app, - with the app in its default state so that the plots are ValidTime, - I want to add two curves, plot unmatched, and then return to the main page. - I then want to add a matched difference curve, plot unmatched, return to the main page, plot matched, and then return to the main page. - I then want to add a piecewise difference curve, plot unmatched, return to the main page, plot matched, and then return to the main page. - I want to end by removing all of the curves. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: matchUnmatchDiffCurvesValidTime - When I set the plot type to "ValidTime" - Then the plot type should be "ValidTime" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I set the curve-dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the curve-dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - When I click the "Add Curve" button - Then "Curve0" is added - - When I change the "data-source" parameter to "CMAQPARA11/148" - Then the "data-source" parameter value matches "CMAQPARA11/148" - When I click the "Add Curve" button - Then "Curve1" is added - And I should see a list of curves containing "Curve0,Curve1" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Valid Time" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Valid Time" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "matching diffs" radio button - Then "Curve1-Curve0" is added - And I should see a list of curves containing "Curve0,Curve1,Curve1-Curve0" - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Valid Time" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Valid Time" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "pairwise diffs" radio button - Then the plot format should be "pairwise" - Then I should see a list of curves containing "Curve0,Curve1,Curve1-Curve0" - And I should have 3 curves - - When I click the "Plot Unmatched" button - Then I should be on the graph page - And I should have a "Valid Time" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - When I click the "Plot Matched" button - Then I should be on the graph page - And I should have a "Valid Time" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Matched" button should be visible - - When I click the "no diffs" radio button - Then I should see a list of curves containing "Curve0,Curve1" - And I should have 2 curves - - When I click the "Remove All" button - And the "Remove all the curves" button should be visible - Then I click the "Remove all the curves" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/plotAddButtonsDisabledWhilePlotting.feature b/tests/src/features/met-airquality/basic/plotAddButtonsDisabledWhilePlotting.feature deleted file mode 100644 index dcbee42e8..000000000 --- a/tests/src/features/met-airquality/basic/plotAddButtonsDisabledWhilePlotting.feature +++ /dev/null @@ -1,49 +0,0 @@ -Feature: Plot and Add buttons are disabled while plotting - - As an unauthenticated user to the app, - with the app in its default state, - I want to add one curve - then plot that curve - and I want to attempt to add a second curve immediately. - The app should disable the add button while it is adding the first curve - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: plotAddButtonsDisabledWhilePlotting - When I set the plot type to "TimeSeries" - Then the plot type should be "TimeSeries" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I set the dates to "04/01/2019 00:00 - 05/09/2019 00:00" - Then the dates value is "04/01/2019 00:00 - 05/09/2019 00:00" - Then I click the "Add Curve" button - Then "Curve0" is added - - When I click the "Plot Unmatched" button - Then the "Add Curve" button should not be enabled - And the "Plot Matched" button should not be enabled - And the "Plot Unmatched" button should not be enabled - Then I should be on the graph page - #The button should be disabled so the second click should have no effect. - And I should have a "Time Series" plot - - When I click the "Back" button - Then I should be on the main page - And the "Plot Unmatched" button should be visible - And the "Plot Matched" button should be visible - And the "Add Curve" button should be visible - And the "Add Curve" button should be enabled - And the "Plot Matched" button should be enabled - And the "Plot Unmatched" button should be enabled - - When I click the "Remove All" button - And the "Remove all the curves" button should be visible - Then I click the "Remove all the curves" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/reloadAndResetToDefaults.feature b/tests/src/features/met-airquality/basic/reloadAndResetToDefaults.feature deleted file mode 100644 index 0b6183111..000000000 --- a/tests/src/features/met-airquality/basic/reloadAndResetToDefaults.feature +++ /dev/null @@ -1,40 +0,0 @@ -Feature: Reload Reset To Defaults - - As an unauthenticated user to the app, - with the app in its default state, - I want to remember the reloaded parameter values of all the params - then I click the "Reset to Defaults" button - then I compare the default parameter values to the reloaded parameter values - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: reloadAndResetToDefaults - Given I remember the parameter values - When I click the "Reset to Defaults" button - Then the parameter values should remain unchanged - When I click the "Add Curve" button - Then "Curve0" is added - When I click the "Remove Curve0" button - And the "Remove curve Curve0" button should be visible - Then I click the "Remove curve Curve0" button - Then I should have 0 curves - - When I refresh the page - And I click the "Add Curve" button - Then "Curve0" is added - Then I click the "Remove Curve0" button - And the "Remove curve Curve0" button should be visible - Then I click the "Remove curve Curve0" button - Then I should have 0 curves - - When I refresh the browser - And I load the app "/met-airquality" - And I click the "Add Curve" button - Then "Curve0" is added - Then I click the "Remove Curve0" button - And the "Remove curve Curve0" button should be visible - Then I click the "Remove curve Curve0" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/exception/noDataFoundException_invalid_times.feature b/tests/src/features/met-airquality/exception/noDataFoundException_invalid_times.feature deleted file mode 100644 index 84eec3e89..000000000 --- a/tests/src/features/met-airquality/exception/noDataFoundException_invalid_times.feature +++ /dev/null @@ -1,46 +0,0 @@ -Feature: No Data Found Exception: invalid_times - - As an unauthenticated user to the app, - with the app in its default state, - I want to change the data-source to HRRR_GSL - I want to change the region to RUC - I want to add one curve - and I click plot unmatched - then see "0 data records found" in the info dialog - then click the "Clear" button - then the info dialog is not visible - and the plot buttons and add curve buttons are enabled. - - Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" - - @watch - Scenario: noDataFoundException_invalid_times - When I set the plot type to "TimeSeries" - Then the plot type should be "TimeSeries" - When I change the "group" parameter to "Test12" - Then the "group" parameter value matches "Test12" - When I change the "database" parameter to "mv_cmaq_g2o" - Then the "database" parameter value matches "mv_cmaq_g2o" - When I change the "data-source" parameter to "CMAQ5X/148" - Then the "data-source" parameter value matches "CMAQ5X/148" - When I set the dates to "01/19/1995 12:00 - 06/19/1996 12:00" - Then the dates value is "01/19/1995 12:00 - 06/19/1996 12:00" - When I click the "Add Curve" button - Then "Curve0" is added - And I should see a list of curves containing "Curve0" - - When I click the "Plot Unmatched" button - Then the "info" dialog should be visible - And I should see "INFO: No valid data for any curves." in the "info" dialog - - When I click the "Clear" button - Then the "info" dialog should not be visible - Then I should be on the main page - And the "Plot Unmatched" button should be visible - - Then I click the "Remove Curve0" button - And the "Remove curve Curve0" button should be visible - Then I click the "Remove curve Curve0" button - Then I should have 0 curves diff --git a/tests/src/features/met-airquality/basic/addRemoveThresholdCurve.feature b/tests/src/features/met-surface/basic/addRemoveThresholdCurve.feature similarity index 85% rename from tests/src/features/met-airquality/basic/addRemoveThresholdCurve.feature rename to tests/src/features/met-surface/basic/addRemoveThresholdCurve.feature index 7d12c521f..ece86e3b9 100644 --- a/tests/src/features/met-airquality/basic/addRemoveThresholdCurve.feature +++ b/tests/src/features/met-surface/basic/addRemoveThresholdCurve.feature @@ -9,8 +9,8 @@ Feature: Add Remove Threshold Curve then delete that curve. Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" + Given I load the app "/met-surface" + Then I expect the app title to be "MET Surface" @watch Scenario: addRemoveThresholdCurve @@ -22,6 +22,8 @@ Feature: Add Remove Threshold Curve Then the "database" parameter value matches "mv_cmaq_g2o" When I change the "data-source" parameter to "CMAQ5X/148" Then the "data-source" parameter value matches "CMAQ5X/148" + When I change the "statistic" parameter to "CSI (Critical Success Index)" + Then the "statistic" parameter value matches "CSI (Critical Success Index)" When I set the curve-dates to "04/01/2019 00:00 - 05/09/2019 00:00" Then the curve-dates value is "04/01/2019 00:00 - 05/09/2019 00:00" Then I click the "Add Curve" button diff --git a/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesThreshold.feature b/tests/src/features/met-surface/basic/matchUnmatchDiffCurvesThreshold.feature similarity index 93% rename from tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesThreshold.feature rename to tests/src/features/met-surface/basic/matchUnmatchDiffCurvesThreshold.feature index 6c346f414..ae8930586 100644 --- a/tests/src/features/met-airquality/basic/matchUnmatchDiffCurvesThreshold.feature +++ b/tests/src/features/met-surface/basic/matchUnmatchDiffCurvesThreshold.feature @@ -8,8 +8,8 @@ Feature: Match Unmatch Diff Curves Threshold I want to end by removing all of the curves. Background: - Given I load the app "/met-airquality" - Then I expect the app title to be "MET Air Quality" + Given I load the app "/met-surface" + Then I expect the app title to be "MET Surface" @watch Scenario: matchUnmatchDiffCurvesThreshold @@ -21,6 +21,8 @@ Feature: Match Unmatch Diff Curves Threshold Then the "database" parameter value matches "mv_cmaq_g2o" When I change the "data-source" parameter to "CMAQ5X/148" Then the "data-source" parameter value matches "CMAQ5X/148" + When I change the "statistic" parameter to "CSI (Critical Success Index)" + Then the "statistic" parameter value matches "CSI (Critical Success Index)" When I set the curve-dates to "04/01/2019 00:00 - 05/09/2019 00:00" Then the curve-dates value is "04/01/2019 00:00 - 05/09/2019 00:00" When I click the "Add Curve" button