Add a shared LRU cache per worker
authorJérôme Benoit <jerome.benoit@sap.com>
Tue, 24 May 2022 19:49:07 +0000 (21:49 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Tue, 24 May 2022 19:49:07 +0000 (21:49 +0200)
And use it to cache CS templates and configuration

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
package-lock.json
package.json
rollup.config.js
src/charging-station/Bootstrap.ts
src/charging-station/ChargingStation.ts
src/charging-station/ChargingStationCache.ts [new file with mode: 0644]
src/charging-station/ChargingStationUtils.ts
src/types/ChargingStationConfiguration.ts
src/types/ChargingStationTemplate.ts
src/utils/Constants.ts
src/utils/Utils.ts

index c624562e7e4af0cf18a031f1345d218f7fbf8620..4e02b7f0d23053f55e819173455781f5dccc79fb 100644 (file)
@@ -9,13 +9,14 @@
       "version": "1.1.60",
       "license": "Apache-2.0",
       "dependencies": {
-        "@mikro-orm/core": "^5.1.3",
-        "@mikro-orm/mariadb": "^5.1.3",
-        "@mikro-orm/reflection": "^5.1.3",
-        "@mikro-orm/sqlite": "^5.1.3",
+        "@mikro-orm/core": "^5.1.4",
+        "@mikro-orm/mariadb": "^5.1.4",
+        "@mikro-orm/reflection": "^5.1.4",
+        "@mikro-orm/sqlite": "^5.1.4",
         "basic-ftp": "^4.6.6",
         "chalk": "^4.1.2",
         "express": "^4.18.1",
+        "mnemonist": "^0.39.1",
         "moment": "^2.29.3",
         "mongodb": "^4.6.0",
         "poolifier": "^2.2.0",
       },
       "devDependencies": {
         "@istanbuljs/nyc-config-typescript": "^1.0.2",
-        "@mikro-orm/cli": "^5.1.3",
+        "@mikro-orm/cli": "^5.1.4",
         "@rollup/plugin-json": "^4.1.0",
         "@types/express": "^4.17.13",
         "@types/mocha": "^9.1.1",
         "@types/mochawesome": "^6.2.1",
-        "@types/node": "^16.11.35",
+        "@types/node": "^16.11.36",
         "@types/proper-lockfile": "^4.1.2",
         "@types/tar": "^6.1.1",
         "@types/uuid": "^8.3.4",
         "@types/ws": "^8.5.3",
-        "@typescript-eslint/eslint-plugin": "^5.24.0",
-        "@typescript-eslint/parser": "^5.24.0",
+        "@typescript-eslint/eslint-plugin": "^5.26.0",
+        "@typescript-eslint/parser": "^5.26.0",
         "auto-changelog": "^2.4.0",
         "clinic": "^11.1.0",
         "cross-env": "^7.0.3",
-        "eslint": "^8.15.0",
+        "eslint": "^8.16.0",
         "eslint-config-prettier": "^8.5.0",
         "eslint-plugin-import": "^2.26.0",
-        "eslint-plugin-jsdoc": "^39.2.9",
+        "eslint-plugin-jsdoc": "^39.3.2",
         "eslint-plugin-node": "^11.1.0",
         "eslint-plugin-prettier": "^4.0.0",
         "expect": "^28.1.0",
         "prettier": "^2.6.2",
         "release-it": "^15.0.0",
         "robohydra": "^0.6.9",
-        "rollup": "^2.73.0",
+        "rollup": "^2.74.1",
         "rollup-plugin-analyzer": "^4.0.0",
         "rollup-plugin-copy": "^3.4.0",
         "rollup-plugin-delete": "^2.0.0",
         "rollup-plugin-istanbul": "^3.0.0",
         "rollup-plugin-terser": "^7.0.2",
         "rollup-plugin-ts": "^2.0.7",
-        "ts-node": "^10.7.0",
+        "ts-node": "^10.8.0",
         "typescript": "^4.6.4"
       },
       "engines": {
       }
     },
     "node_modules/@babel/core": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.12.tgz",
-      "integrity": "sha512-44ODe6O1IVz9s2oJE3rZ4trNNKTX9O7KpQpfAP4t8QII/zwrVRHL7i2pxhqtcY7tqMLrrKfMlBKnm1QlrRFs5w==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.0.tgz",
+      "integrity": "sha512-Xyw74OlJwDijToNi0+6BBI5mLLR5+5R3bcSH80LXzjzEGEUlvNzujEE71BaD/ApEZHAvFI/Mlmp4M5lIkdeeWw==",
       "dev": true,
       "dependencies": {
         "@ampproject/remapping": "^2.1.0",
         "@babel/code-frame": "^7.16.7",
-        "@babel/generator": "^7.17.12",
+        "@babel/generator": "^7.18.0",
         "@babel/helper-compilation-targets": "^7.17.10",
-        "@babel/helper-module-transforms": "^7.17.12",
-        "@babel/helpers": "^7.17.9",
-        "@babel/parser": "^7.17.12",
+        "@babel/helper-module-transforms": "^7.18.0",
+        "@babel/helpers": "^7.18.0",
+        "@babel/parser": "^7.18.0",
         "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.12",
-        "@babel/types": "^7.17.12",
+        "@babel/traverse": "^7.18.0",
+        "@babel/types": "^7.18.0",
         "convert-source-map": "^1.7.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.2",
       }
     },
     "node_modules/@babel/generator": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.12.tgz",
-      "integrity": "sha512-V49KtZiiiLjH/CnIW6OjJdrenrGoyh6AmKQ3k2AZFKozC1h846Q4NYlZ5nqAigPDUXfGzC88+LOUuG8yKd2kCw==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.0.tgz",
+      "integrity": "sha512-81YO9gGx6voPXlvYdZBliFXAZU8vZ9AZ6z+CjlmcnaeOcYSFbMTpdeDUO9xD9dh/68Vq03I8ZspfUTPfitcDHg==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.17.12",
+        "@babel/types": "^7.18.0",
         "@jridgewell/gen-mapping": "^0.3.0",
         "jsesc": "^2.5.1"
       },
       }
     },
     "node_modules/@babel/helper-module-transforms": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.12.tgz",
-      "integrity": "sha512-t5s2BeSWIghhFRPh9XMn6EIGmvn8Lmw5RVASJzkIx1mSemubQQBNIZiQD7WzaFmaHIrjAec4x8z9Yx8SjJ1/LA==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz",
+      "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==",
       "dev": true,
       "dependencies": {
         "@babel/helper-environment-visitor": "^7.16.7",
         "@babel/helper-split-export-declaration": "^7.16.7",
         "@babel/helper-validator-identifier": "^7.16.7",
         "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.12",
-        "@babel/types": "^7.17.12"
+        "@babel/traverse": "^7.18.0",
+        "@babel/types": "^7.18.0"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helpers": {
-      "version": "7.17.9",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz",
-      "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.0.tgz",
+      "integrity": "sha512-AE+HMYhmlMIbho9nbvicHyxFwhrO+xhKB6AhRxzl8w46Yj0VXTZjEsAoBVC7rB2I0jzX+yWyVybnO08qkfx6kg==",
       "dev": true,
       "dependencies": {
         "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.9",
-        "@babel/types": "^7.17.0"
+        "@babel/traverse": "^7.18.0",
+        "@babel/types": "^7.18.0"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/parser": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.12.tgz",
-      "integrity": "sha512-FLzHmN9V3AJIrWfOpvRlZCeVg/WLdicSnTMsLur6uDj9TT8ymUlG9XxURdW/XvuygK+2CW0poOJABdA4m/YKxA==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.0.tgz",
+      "integrity": "sha512-AqDccGC+m5O/iUStSJy3DGRIUFu7WbY/CppZYwrEUB4N0tZlnI8CSTsgL7v5fHVFmUbRv2sd+yy27o8Ydt4MGg==",
       "dev": true,
       "bin": {
         "parser": "bin/babel-parser.js"
       }
     },
     "node_modules/@babel/traverse": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.12.tgz",
-      "integrity": "sha512-zULPs+TbCvOkIFd4FrG53xrpxvCBwLIgo6tO0tJorY7YV2IWFxUfS/lXDJbGgfyYt9ery/Gxj2niwttNnB0gIw==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.0.tgz",
+      "integrity": "sha512-oNOO4vaoIQoGjDQ84LgtF/IAlxlyqL4TUuoQ7xLkQETFaHkY1F7yazhB4Kt3VcZGL0ZF/jhrEpnXqUb0M7V3sw==",
       "dev": true,
       "dependencies": {
         "@babel/code-frame": "^7.16.7",
-        "@babel/generator": "^7.17.12",
+        "@babel/generator": "^7.18.0",
         "@babel/helper-environment-visitor": "^7.16.7",
         "@babel/helper-function-name": "^7.17.9",
         "@babel/helper-hoist-variables": "^7.16.7",
         "@babel/helper-split-export-declaration": "^7.16.7",
-        "@babel/parser": "^7.17.12",
-        "@babel/types": "^7.17.12",
+        "@babel/parser": "^7.18.0",
+        "@babel/types": "^7.18.0",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       },
       }
     },
     "node_modules/@babel/types": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.12.tgz",
-      "integrity": "sha512-rH8i29wcZ6x9xjzI5ILHL/yZkbQnCERdHlogKuIb4PUr7do4iT8DPekrTbBLWTnRQm6U0GYABbTMSzijmEqlAg==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.0.tgz",
+      "integrity": "sha512-vhAmLPAiC8j9K2GnsnLPCIH5wCrPpYIVBCWRBFDCB7Y/BXLqi/O+1RSTTM2bsmg6U/551+FCf9PNPxjABmxHTw==",
       "dev": true,
       "dependencies": {
         "@babel/helper-validator-identifier": "^7.16.7",
         "node": ">=0.1.90"
       }
     },
-    "node_modules/@cspotcode/source-map-consumer": {
-      "version": "0.8.0",
-      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
-      "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
-      "dev": true,
-      "engines": {
-        "node": ">= 12"
-      }
-    },
     "node_modules/@cspotcode/source-map-support": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
-      "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+      "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
       "dev": true,
       "dependencies": {
-        "@cspotcode/source-map-consumer": "0.8.0"
+        "@jridgewell/trace-mapping": "0.3.9"
       },
       "engines": {
         "node": ">=12"
       }
     },
     "node_modules/@es-joy/jsdoccomment": {
-      "version": "0.29.0",
-      "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.29.0.tgz",
-      "integrity": "sha512-4yKy5t+/joLihG+ei6CCU6sc08sjUdEdXCQ2U+9h9VP13EiqHQ4YMgDC18ys/AsLdJDBX3KRx/AWY6PR7hn52Q==",
+      "version": "0.31.0",
+      "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz",
+      "integrity": "sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ==",
       "dev": true,
       "dependencies": {
         "comment-parser": "1.3.1",
         "esquery": "^1.4.0",
-        "jsdoc-type-pratt-parser": "~3.0.1"
+        "jsdoc-type-pratt-parser": "~3.1.0"
       },
       "engines": {
         "node": "^14 || ^16 || ^17 || ^18"
       }
     },
     "node_modules/@eslint/eslintrc": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz",
-      "integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==",
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
+      "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
       "dev": true,
       "dependencies": {
         "ajv": "^6.12.4",
         "debug": "^4.3.2",
         "espree": "^9.3.2",
-        "globals": "^13.9.0",
+        "globals": "^13.15.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.2.1",
         "js-yaml": "^4.1.0",
       "dev": true
     },
     "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.13",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz",
-      "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==",
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+      "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
       "dev": true,
       "dependencies": {
         "@jridgewell/resolve-uri": "^3.0.3",
       }
     },
     "node_modules/@mdn/browser-compat-data": {
-      "version": "4.1.20",
-      "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-4.1.20.tgz",
-      "integrity": "sha512-9VOi5TU0xE/XhShmGQpNAa3PduouSxDrEK0p7mVZe4ndhH8xV87fYb3vyYyL8i4wyRT7fHG8vyecVTRMLy04Mg==",
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-4.2.1.tgz",
+      "integrity": "sha512-EWUguj2kd7ldmrF9F+vI5hUOralPd+sdsUnYbRy33vZTuZkduC1shE9TtEMEjAQwyfyMb4ole5KtjF8MsnQOlA==",
       "dev": true
     },
     "node_modules/@mikro-orm/cli": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-5.1.3.tgz",
-      "integrity": "sha512-GNAVg0hjdQrvkEvzIdec3LafocLHSZkojA+699LMoSgH9YrtOQnk/luBssdJSTJgHngb2twWlM6KCLjFSzIV5Q==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-5.1.4.tgz",
+      "integrity": "sha512-5x8B4pmyogqnp2fuulx5WD7Y2SqHEpOj67VQzkRXKUFJXDfMel2Ydp7HrknrJwn0dumB5H/MoIBLQ/Y9qFDoVg==",
       "dev": true,
       "dependencies": {
-        "@mikro-orm/core": "^5.1.3",
-        "@mikro-orm/knex": "^5.1.3",
+        "@mikro-orm/core": "^5.1.4",
+        "@mikro-orm/knex": "^5.1.4",
         "fs-extra": "10.1.0",
-        "tsconfig-paths": "3.14.1",
+        "tsconfig-paths": "4.0.0",
         "yargonaut": "1.1.4",
         "yargs": "15.4.1"
       },
       }
     },
     "node_modules/@mikro-orm/core": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-5.1.3.tgz",
-      "integrity": "sha512-N10ejP9EraJ5icnfjjR5v+8X5VE6fu31W5R3gi6Gd/FOsqUmUx2KEGTEA6j4f6PDstX1tKCyo9G+98LfNwmr4A==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-5.1.4.tgz",
+      "integrity": "sha512-D/nIjjAAehPQ0g51iDJrp6XS+KEfza349H2ykOd2Hztf/PnuYE5z+2HrVrAp/5GxF1Be0kD/E1CPHGFoNQMvsA==",
       "dependencies": {
-        "dotenv": "16.0.0",
+        "dotenv": "16.0.1",
         "escaya": "0.0.61",
         "fs-extra": "10.1.0",
         "globby": "11.0.4",
-        "mikro-orm": "^5.1.2",
+        "mikro-orm": "^5.1.4",
         "reflect-metadata": "0.1.13"
       },
       "engines": {
       }
     },
     "node_modules/@mikro-orm/knex": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-5.1.3.tgz",
-      "integrity": "sha512-wBJsvETrx6NIdThBrrUk49kLrPY1PyL9R+su9D3b/oIfdB2W3m+KaUu8ybju0rB2K26giWNONtbyd9eKd8PrIw==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-5.1.4.tgz",
+      "integrity": "sha512-5+E4E/Hn+SfuKOSBfCaOnmAmr1ZOtRw5XWtpKdo8u1GoHQZlnu7Pv45BEbjlTDpKnumIBx4bJYsXNMXyGypOBQ==",
       "dependencies": {
         "fs-extra": "10.1.0",
         "knex": "2.0.0",
       }
     },
     "node_modules/@mikro-orm/mariadb": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/mariadb/-/mariadb-5.1.3.tgz",
-      "integrity": "sha512-eXt4HaLJnI2mgb9EUlvfFgtW2WkKojcp07+8d/3LVyuhHqGQ8+JwOqMWHoGopoqSwtAp1E8iT+kCfHeU8xOBkw==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/mariadb/-/mariadb-5.1.4.tgz",
+      "integrity": "sha512-Z3ZJUfDeDHmUSj18K4tltdcj0fZRZ/ojRKtD13OVpEdnKneztdh/gTAJIXS40b7FMb3rVDY+Xq5Cpp1mPWVAzQ==",
       "dependencies": {
-        "@mikro-orm/knex": "^5.1.3",
+        "@mikro-orm/knex": "^5.1.4",
         "mariadb": "2.5.6"
       },
       "engines": {
       }
     },
     "node_modules/@mikro-orm/reflection": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-5.1.3.tgz",
-      "integrity": "sha512-PlWMuEpY3Y7DmITENtG12kiOvkZUa3j6+J/YfA+WyRwZVyBSbWG5haHBcglbMzA0pe22IT/BX47eQd7IGXfosQ==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-5.1.4.tgz",
+      "integrity": "sha512-/w0sehByYsEmE1rX6yPzXCAjqmq62Zo7soiJN9AchMAJOzuXWlmyQ7gDfGVsx8ojglOSkij0n4u6VKogxIwZeg==",
       "dependencies": {
         "globby": "11.0.4",
         "ts-morph": "14.0.0"
       }
     },
     "node_modules/@mikro-orm/sqlite": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/sqlite/-/sqlite-5.1.3.tgz",
-      "integrity": "sha512-/QQXxFdjQogdUxDL7RZ+V0Qj5tCFCnXBAsaRtsvcxPgwEEhdmSYydKV8xtCT5O9VJCOOFCsbwvag02l3dOLtKA==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/sqlite/-/sqlite-5.1.4.tgz",
+      "integrity": "sha512-xijE6amwHIbKyVdPhXpM+wD1hzgBGdx1UCPs8pu8tMBrCtLLNJTOq7odA5SEtx0Er9dfv3I9RkPz1DGC3lzsaQ==",
       "dependencies": {
-        "@mikro-orm/knex": "^5.1.3",
+        "@mikro-orm/knex": "^5.1.4",
         "fs-extra": "10.1.0",
-        "sqlite3": "5.0.5",
+        "sqlite3": "5.0.8",
         "sqlstring-sqlite": "0.1.1"
       },
       "engines": {
       }
     },
     "node_modules/@tensorflow/tfjs-backend-cpu": {
-      "version": "3.17.0",
-      "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.17.0.tgz",
-      "integrity": "sha512-alfmaPLnsa/DvkhnPoX/r9ZVDcSuRZUJEElaG3o84JrCBOqzq2jcFwaT9KxchN8rDLmKjJMLQkcQx/bSp/Oz4w==",
+      "version": "3.18.0",
+      "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.18.0.tgz",
+      "integrity": "sha512-LcSqlylzGtpgngcMFIL3q9Q3eVaPRJ7ITZt7ivhzkCj4R5ZsnPa9qM3DCVihkQ77heAwSw4hPTo2jp5C4mJ4Cg==",
       "dev": true,
       "dependencies": {
         "@types/seedrandom": "2.4.27",
         "yarn": ">= 1.3.2"
       },
       "peerDependencies": {
-        "@tensorflow/tfjs-core": "3.17.0"
+        "@tensorflow/tfjs-core": "3.18.0"
       }
     },
     "node_modules/@tensorflow/tfjs-core": {
-      "version": "3.17.0",
-      "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-3.17.0.tgz",
-      "integrity": "sha512-PMqEDysVy3WsSK4pU+UaoINRjps1RTF2CPvS1sWgOJqc/rUz8mSMibMosti0Is6DHGw7UiAq53y9VMuzQRVJqA==",
+      "version": "3.18.0",
+      "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-3.18.0.tgz",
+      "integrity": "sha512-gMxisZozqsr5sCKlphF/eVBLg91MjlBiN60tjX8hJAu0WlSn6Gi5k65GNIL+Pq6hrxpvImcfdCmTH/2XJVZ0Mg==",
       "dev": true,
       "dependencies": {
         "@types/long": "^4.0.1",
       }
     },
     "node_modules/@types/node": {
-      "version": "16.11.35",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.35.tgz",
-      "integrity": "sha512-QXu45LyepgnhUfnIAj/FyT4uM87ug5KpIrgXfQtUPNAlx8w5hmd8z8emqCLNvG11QkpRSCG9Qg2buMxvqfjfsQ=="
+      "version": "16.11.36",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.36.tgz",
+      "integrity": "sha512-FR5QJe+TaoZ2GsMHkjuwoNabr+UrJNRr2HNOo+r/7vhcuntM6Ee/pRPOnRhhL2XE9OOvX9VLEq+BcXl3VjNoWA=="
     },
     "node_modules/@types/object-path": {
       "version": "0.11.1",
       "dev": true
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.24.0.tgz",
-      "integrity": "sha512-6bqFGk6wa9+6RrU++eLknKyDqXU1Oc8nyoLu5a1fU17PNRJd9UBr56rMF7c4DRaRtnarlkQ4jwxUbvBo8cNlpw==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.26.0.tgz",
+      "integrity": "sha512-oGCmo0PqnRZZndr+KwvvAUvD3kNE4AfyoGCwOZpoCncSh4MVD06JTE8XQa2u9u+NX5CsyZMBTEc2C72zx38eYA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "5.24.0",
-        "@typescript-eslint/type-utils": "5.24.0",
-        "@typescript-eslint/utils": "5.24.0",
+        "@typescript-eslint/scope-manager": "5.26.0",
+        "@typescript-eslint/type-utils": "5.26.0",
+        "@typescript-eslint/utils": "5.26.0",
         "debug": "^4.3.4",
         "functional-red-black-tree": "^1.0.1",
         "ignore": "^5.2.0",
       }
     },
     "node_modules/@typescript-eslint/parser": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.24.0.tgz",
-      "integrity": "sha512-4q29C6xFYZ5B2CXqSBBdcS0lPyfM9M09DoQLtHS5kf+WbpV8pBBhHDLNhXfgyVwFnhrhYzOu7xmg02DzxeF2Uw==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.26.0.tgz",
+      "integrity": "sha512-n/IzU87ttzIdnAH5vQ4BBDnLPly7rC5VnjN3m0xBG82HK6rhRxnCb3w/GyWbNDghPd+NktJqB/wl6+YkzZ5T5Q==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "5.24.0",
-        "@typescript-eslint/types": "5.24.0",
-        "@typescript-eslint/typescript-estree": "5.24.0",
+        "@typescript-eslint/scope-manager": "5.26.0",
+        "@typescript-eslint/types": "5.26.0",
+        "@typescript-eslint/typescript-estree": "5.26.0",
         "debug": "^4.3.4"
       },
       "engines": {
       }
     },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.24.0.tgz",
-      "integrity": "sha512-WpMWipcDzGmMzdT7NtTjRXFabx10WleLUGrJpuJLGaxSqpcyq5ACpKSD5VE40h2nz3melQ91aP4Du7lh9FliCA==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.26.0.tgz",
+      "integrity": "sha512-gVzTJUESuTwiju/7NiTb4c5oqod8xt5GhMbExKsCTp6adU3mya6AGJ4Pl9xC7x2DX9UYFsjImC0mA62BCY22Iw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.24.0",
-        "@typescript-eslint/visitor-keys": "5.24.0"
+        "@typescript-eslint/types": "5.26.0",
+        "@typescript-eslint/visitor-keys": "5.26.0"
       },
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.24.0.tgz",
-      "integrity": "sha512-uGi+sQiM6E5CeCZYBXiaIvIChBXru4LZ1tMoeKbh1Lze+8BO9syUG07594C4lvN2YPT4KVeIupOJkVI+9/DAmQ==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.26.0.tgz",
+      "integrity": "sha512-7ccbUVWGLmcRDSA1+ADkDBl5fP87EJt0fnijsMFTVHXKGduYMgienC/i3QwoVhDADUAPoytgjbZbCOMj4TY55A==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/utils": "5.24.0",
+        "@typescript-eslint/utils": "5.26.0",
         "debug": "^4.3.4",
         "tsutils": "^3.21.0"
       },
       }
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.24.0.tgz",
-      "integrity": "sha512-Tpg1c3shTDgTmZd3qdUyd+16r/pGmVaVEbLs+ufuWP0EruVbUiEOmpBBQxBb9a8iPRxi8Rb2oiwOxuZJzSq11A==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.26.0.tgz",
+      "integrity": "sha512-8794JZFE1RN4XaExLWLI2oSXsVImNkl79PzTOOWt9h0UHROwJedNOD2IJyfL0NbddFllcktGIO2aOu10avQQyA==",
       "dev": true,
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.24.0.tgz",
-      "integrity": "sha512-zcor6vQkQmZAQfebSPVwUk/FD+CvnsnlfKXYeQDsWXRF+t7SBPmIfNia/wQxCSeu1h1JIjwV2i9f5/DdSp/uDw==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.26.0.tgz",
+      "integrity": "sha512-EyGpw6eQDsfD6jIqmXP3rU5oHScZ51tL/cZgFbFBvWuCwrIptl+oueUZzSmLtxFuSOQ9vDcJIs+279gnJkfd1w==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.24.0",
-        "@typescript-eslint/visitor-keys": "5.24.0",
+        "@typescript-eslint/types": "5.26.0",
+        "@typescript-eslint/visitor-keys": "5.26.0",
         "debug": "^4.3.4",
         "globby": "^11.1.0",
         "is-glob": "^4.0.3",
       }
     },
     "node_modules/@typescript-eslint/utils": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.24.0.tgz",
-      "integrity": "sha512-K05sbWoeCBJH8KXu6hetBJ+ukG0k2u2KlgD3bN+v+oBKm8adJqVHpSSLHNzqyuv0Lh4GVSAUgZ5lB4icmPmWLw==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.26.0.tgz",
+      "integrity": "sha512-PJFwcTq2Pt4AMOKfe3zQOdez6InIDOjUJJD3v3LyEtxHGVVRK3Vo7Dd923t/4M9hSH2q2CLvcTdxlLPjcIk3eg==",
       "dev": true,
       "dependencies": {
         "@types/json-schema": "^7.0.9",
-        "@typescript-eslint/scope-manager": "5.24.0",
-        "@typescript-eslint/types": "5.24.0",
-        "@typescript-eslint/typescript-estree": "5.24.0",
+        "@typescript-eslint/scope-manager": "5.26.0",
+        "@typescript-eslint/types": "5.26.0",
+        "@typescript-eslint/typescript-estree": "5.26.0",
         "eslint-scope": "^5.1.1",
         "eslint-utils": "^3.0.0"
       },
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.24.0.tgz",
-      "integrity": "sha512-qzGwSXMyMnogcAo+/2fU+jhlPPVMXlIH2PeAonIKjJSoDKl1+lJVvG5Z5Oud36yU0TWK2cs1p/FaSN5J2OUFYA==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.26.0.tgz",
+      "integrity": "sha512-wei+ffqHanYDOQgg/fS6Hcar6wAWv0CUPQ3TZzOWd2BLfgP539rb49bwua8WRAs7R6kOSLn82rfEu2ro6Llt8Q==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.24.0",
+        "@typescript-eslint/types": "5.26.0",
         "eslint-visitor-keys": "^3.3.0"
       },
       "engines": {
       "dev": true
     },
     "node_modules/@webgpu/types": {
-      "version": "0.1.16",
-      "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.16.tgz",
-      "integrity": "sha512-9E61voMP4+Rze02jlTXud++Htpjyyk8vw5Hyw9FGRrmhHQg2GqbuOfwf5Klrb8vTxc2XWI3EfO7RUHMpxTj26A==",
+      "version": "0.1.17",
+      "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.17.tgz",
+      "integrity": "sha512-M8INbXsMdkWtVsSHRPEiTXHe0S4gxMhYA/Kz4pNoUF9IXd3PHMi6/2n8EAsqkAEdna+aeCm2RmscWV0hsmIf0Q==",
       "dev": true
     },
     "node_modules/@wessberg/stringutil": {
       }
     },
     "node_modules/bn.js": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
-      "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==",
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+      "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
       "dev": true
     },
     "node_modules/body-parser": {
       }
     },
     "node_modules/bson": {
-      "version": "4.6.3",
-      "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.3.tgz",
-      "integrity": "sha512-rAqP5hcUVJhXP2MCSNVsf0oM2OGU1So6A9pVRDYayvJ5+hygXHQApf87wd5NlhPM1J9RJnbqxIG/f8QTzRoQ4A==",
+      "version": "4.6.4",
+      "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.4.tgz",
+      "integrity": "sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ==",
       "dependencies": {
         "buffer": "^5.6.0"
       },
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001341",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz",
-      "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==",
+      "version": "1.0.30001342",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001342.tgz",
+      "integrity": "sha512-bn6sOCu7L7jcbBbyNhLg0qzXdJ/PMbybZTH/BA6Roet9wxYRm6Tr9D0s0uhLkOZ6MSG+QU6txUgdpr3MXIVqjA==",
       "dev": true,
       "funding": [
         {
       }
     },
     "node_modules/dotenv": {
-      "version": "16.0.0",
-      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz",
-      "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==",
+      "version": "16.0.1",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz",
+      "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==",
       "engines": {
         "node": ">=12"
       }
       }
     },
     "node_modules/es-abstract": {
-      "version": "1.20.0",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.0.tgz",
-      "integrity": "sha512-URbD8tgRthKD3YcC39vbvSDrX23upXnPcnGAjQfgxXF5ID75YcENawc9ZX/9iTP9ptUyfCLIxTTuMYoRfiOVKA==",
+      "version": "1.20.1",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz",
+      "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==",
       "dev": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "object-inspect": "^1.12.0",
         "object-keys": "^1.1.1",
         "object.assign": "^4.1.2",
-        "regexp.prototype.flags": "^1.4.1",
+        "regexp.prototype.flags": "^1.4.3",
         "string.prototype.trimend": "^1.0.5",
         "string.prototype.trimstart": "^1.0.5",
         "unbox-primitive": "^1.0.2"
       }
     },
     "node_modules/eslint": {
-      "version": "8.15.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz",
-      "integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==",
+      "version": "8.16.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz",
+      "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==",
       "dev": true,
       "dependencies": {
-        "@eslint/eslintrc": "^1.2.3",
+        "@eslint/eslintrc": "^1.3.0",
         "@humanwhocodes/config-array": "^0.9.2",
         "ajv": "^6.10.0",
         "chalk": "^4.0.0",
         "file-entry-cache": "^6.0.1",
         "functional-red-black-tree": "^1.0.1",
         "glob-parent": "^6.0.1",
-        "globals": "^13.6.0",
+        "globals": "^13.15.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.0.0",
         "imurmurhash": "^0.1.4",
         "node": ">=0.10.0"
       }
     },
+    "node_modules/eslint-plugin-import/node_modules/json5": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+      "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+      "dev": true,
+      "dependencies": {
+        "minimist": "^1.2.0"
+      },
+      "bin": {
+        "json5": "lib/cli.js"
+      }
+    },
     "node_modules/eslint-plugin-import/node_modules/ms": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
       "dev": true
     },
+    "node_modules/eslint-plugin-import/node_modules/strip-bom": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+      "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
+      "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/json5": "^0.0.29",
+        "json5": "^1.0.1",
+        "minimist": "^1.2.6",
+        "strip-bom": "^3.0.0"
+      }
+    },
     "node_modules/eslint-plugin-jsdoc": {
-      "version": "39.2.9",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.2.9.tgz",
-      "integrity": "sha512-gaPYJT94rWlWyQcisQyyEJHtLaaJqN4baFlLCEr/LcXVibS9wzQTL2dskqk327ggwqQopR+Xecu2Lng1IJ9Ypw==",
+      "version": "39.3.2",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.2.tgz",
+      "integrity": "sha512-RSGN94RYzIJS/WfW3l6cXzRLfJWxvJgNQZ4w0WCaxJWDJMigtwTsILEAfKqmmPkT2rwMH/s3C7G5ChDE6cwPJg==",
       "dev": true,
       "dependencies": {
-        "@es-joy/jsdoccomment": "~0.29.0",
+        "@es-joy/jsdoccomment": "~0.31.0",
         "comment-parser": "1.3.1",
         "debug": "^4.3.4",
         "escape-string-regexp": "^4.0.0",
       "dev": true
     },
     "node_modules/jsdoc-type-pratt-parser": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.0.1.tgz",
-      "integrity": "sha512-vqMCdAFVIiFhVgBYE/X8naf3L/7qiJsaYWTfUJZZZ124dR3OUz9HrmaMUGpYIYAN4VSuodf6gIZY0e8ktPw9cg==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz",
+      "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==",
       "dev": true,
       "engines": {
         "node": ">=12.0.0"
       }
     },
     "node_modules/keyv": {
-      "version": "4.2.8",
-      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.2.8.tgz",
-      "integrity": "sha512-IZZo6krhHWPhgsP5mBkEdPopVPN/stgCnBVuqi6dda/Nm5mDTOSVTrFMkWqlJsDum+B0YSe887tNxdjDWkO7aQ==",
+      "version": "4.2.9",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.2.9.tgz",
+      "integrity": "sha512-vqRBrN4xQHud7UMAGzGGFbt96MtGB9pb0OOg8Dhtq5RtiswCb1pCFq878iqC4hdeOP6eDPnCoFxA+2TXx427Ow==",
       "dev": true,
       "dependencies": {
         "compress-brotli": "^1.3.8",
       }
     },
     "node_modules/mariadb/node_modules/@types/node": {
-      "version": "17.0.33",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.33.tgz",
-      "integrity": "sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ=="
+      "version": "17.0.35",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz",
+      "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg=="
     },
     "node_modules/mariadb/node_modules/iconv-lite": {
       "version": "0.6.3",
       }
     },
     "node_modules/mikro-orm": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-5.1.2.tgz",
-      "integrity": "sha512-Qyy+EZeBRiyzLstX9Ug9vyDvmz9SIgK4g/h4oMSjgv/VyMwboUuIi4NSXc8HqrpolTdotmcsEzM3d23DUZYSsQ==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-5.1.4.tgz",
+      "integrity": "sha512-etO+2eooBMf/dHJmLbnRsk9P8rf9oYJn1lJ13gEUuBUE7+Rqs7XXqGMR2AFiEbhLU1ZxH58rWOODLZd5zl+V7g==",
       "engines": {
         "node": ">= 14.0.0"
       }
       "integrity": "sha512-VoAYUqmPRmzKbbqRejjqceGFp3VF81Qe8XXFGU0UXLxB7Mf4GGvyGq5Qn3k4AiQgDEV6WzobqlPOd+j0+m6IrA==",
       "dev": true
     },
+    "node_modules/mnemonist": {
+      "version": "0.39.1",
+      "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.1.tgz",
+      "integrity": "sha512-bY13FSvcbKLj+FaJcR2+xFZ3m2R1+BrLpavAh0BMyGSq0iPowbvYllwitlkvVyEowEYSulCMzxDaju9bC4+cow==",
+      "dependencies": {
+        "obliterator": "^2.0.1"
+      }
+    },
     "node_modules/mocha": {
       "version": "10.0.0",
       "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz",
       }
     },
     "node_modules/node-releases": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz",
-      "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz",
+      "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==",
       "dev": true
     },
     "node_modules/nopt": {
       }
     },
     "node_modules/object-inspect": {
-      "version": "1.12.0",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
-      "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.1.tgz",
+      "integrity": "sha512-Y/jF6vnvEtOPGiKD1+q+X0CiUYRQtEHp89MLLUJ7TUivtH8Ugn2+3A7Rynqk7BRsAoqeOQWnFnjpDrKSxDgIGA==",
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/obliterator": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz",
+      "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ=="
+    },
     "node_modules/on-finished": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
       }
     },
     "node_modules/postcss": {
-      "version": "8.4.13",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.13.tgz",
-      "integrity": "sha512-jtL6eTBrza5MPzy8oJLFuUscHDXTV5KcLlqAWHl5q5WYRfnNRGSmOZmOZ1T6Gy7A99mOZfqungmZMpMmCVJ8ZA==",
+      "version": "8.4.14",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
+      "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
       "dev": true,
       "funding": [
         {
         }
       ],
       "dependencies": {
-        "nanoid": "^3.3.3",
+        "nanoid": "^3.3.4",
         "picocolors": "^1.0.0",
         "source-map-js": "^1.0.2"
       },
       "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
       "dev": true
     },
+    "node_modules/postcss/node_modules/nanoid": {
+      "version": "3.3.4",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
+      "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
+      "dev": true,
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
     "node_modules/prelude-ls": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
       }
     },
     "node_modules/rollup": {
-      "version": "2.73.0",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.73.0.tgz",
-      "integrity": "sha512-h/UngC3S4Zt28mB3g0+2YCMegT5yoftnQplwzPqGZcKvlld5e+kT/QRmJiL+qxGyZKOYpgirWGdLyEO1b0dpLQ==",
+      "version": "2.74.1",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.74.1.tgz",
+      "integrity": "sha512-K2zW7kV8Voua5eGkbnBtWYfMIhYhT9Pel2uhBk2WO5eMee161nPze/XRfvEQPFYz7KgrCCnmh2Wy0AMFLGGmMA==",
       "dev": true,
       "bin": {
         "rollup": "dist/bin/rollup"
       "dev": true
     },
     "node_modules/sqlite3": {
-      "version": "5.0.5",
-      "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.5.tgz",
-      "integrity": "sha512-ZZFOMW31IOMbUeSiL23TuWSjNyS7Z83EDJ80HJxCe78OZ+5BJT6IhAwAUnQgPsUl5z+Er0DGx7VjuTP7PKPNcg==",
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.8.tgz",
+      "integrity": "sha512-f2ACsbSyb2D1qFFcqIXPfFscLtPVOWJr5GmUzYxf4W+0qelu5MWrR+FAQE1d5IUArEltBrzSDxDORG8P/IkqyQ==",
       "hasInstallScript": true,
       "dependencies": {
         "@mapbox/node-pre-gyp": "^1.0.0",
       }
     },
     "node_modules/ts-node": {
-      "version": "10.7.0",
-      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz",
-      "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==",
+      "version": "10.8.0",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.0.tgz",
+      "integrity": "sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==",
       "dev": true,
       "dependencies": {
-        "@cspotcode/source-map-support": "0.7.0",
+        "@cspotcode/source-map-support": "^0.8.0",
         "@tsconfig/node10": "^1.0.7",
         "@tsconfig/node12": "^1.0.7",
         "@tsconfig/node14": "^1.0.0",
         "create-require": "^1.1.0",
         "diff": "^4.0.1",
         "make-error": "^1.1.1",
-        "v8-compile-cache-lib": "^3.0.0",
+        "v8-compile-cache-lib": "^3.0.1",
         "yn": "3.1.1"
       },
       "bin": {
       }
     },
     "node_modules/tsconfig-paths": {
-      "version": "3.14.1",
-      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
-      "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.0.0.tgz",
+      "integrity": "sha512-SLBg2GBKlR6bVtMgJJlud/o3waplKtL7skmLkExomIiaAtLGtVsoXIqP3SYdjbcH9lq/KVv7pMZeCBpLYOit6Q==",
       "dev": true,
       "dependencies": {
-        "@types/json5": "^0.0.29",
-        "json5": "^1.0.1",
+        "json5": "^2.2.1",
         "minimist": "^1.2.6",
         "strip-bom": "^3.0.0"
       }
     },
-    "node_modules/tsconfig-paths/node_modules/json5": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-      "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-      "dev": true,
-      "dependencies": {
-        "minimist": "^1.2.0"
-      },
-      "bin": {
-        "json5": "lib/cli.js"
-      }
-    },
     "node_modules/tsconfig-paths/node_modules/strip-bom": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
       "dev": true
     },
     "@babel/core": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.12.tgz",
-      "integrity": "sha512-44ODe6O1IVz9s2oJE3rZ4trNNKTX9O7KpQpfAP4t8QII/zwrVRHL7i2pxhqtcY7tqMLrrKfMlBKnm1QlrRFs5w==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.0.tgz",
+      "integrity": "sha512-Xyw74OlJwDijToNi0+6BBI5mLLR5+5R3bcSH80LXzjzEGEUlvNzujEE71BaD/ApEZHAvFI/Mlmp4M5lIkdeeWw==",
       "dev": true,
       "requires": {
         "@ampproject/remapping": "^2.1.0",
         "@babel/code-frame": "^7.16.7",
-        "@babel/generator": "^7.17.12",
+        "@babel/generator": "^7.18.0",
         "@babel/helper-compilation-targets": "^7.17.10",
-        "@babel/helper-module-transforms": "^7.17.12",
-        "@babel/helpers": "^7.17.9",
-        "@babel/parser": "^7.17.12",
+        "@babel/helper-module-transforms": "^7.18.0",
+        "@babel/helpers": "^7.18.0",
+        "@babel/parser": "^7.18.0",
         "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.12",
-        "@babel/types": "^7.17.12",
+        "@babel/traverse": "^7.18.0",
+        "@babel/types": "^7.18.0",
         "convert-source-map": "^1.7.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.2",
       }
     },
     "@babel/generator": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.12.tgz",
-      "integrity": "sha512-V49KtZiiiLjH/CnIW6OjJdrenrGoyh6AmKQ3k2AZFKozC1h846Q4NYlZ5nqAigPDUXfGzC88+LOUuG8yKd2kCw==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.0.tgz",
+      "integrity": "sha512-81YO9gGx6voPXlvYdZBliFXAZU8vZ9AZ6z+CjlmcnaeOcYSFbMTpdeDUO9xD9dh/68Vq03I8ZspfUTPfitcDHg==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.17.12",
+        "@babel/types": "^7.18.0",
         "@jridgewell/gen-mapping": "^0.3.0",
         "jsesc": "^2.5.1"
       },
       }
     },
     "@babel/helper-module-transforms": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.12.tgz",
-      "integrity": "sha512-t5s2BeSWIghhFRPh9XMn6EIGmvn8Lmw5RVASJzkIx1mSemubQQBNIZiQD7WzaFmaHIrjAec4x8z9Yx8SjJ1/LA==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz",
+      "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==",
       "dev": true,
       "requires": {
         "@babel/helper-environment-visitor": "^7.16.7",
         "@babel/helper-split-export-declaration": "^7.16.7",
         "@babel/helper-validator-identifier": "^7.16.7",
         "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.12",
-        "@babel/types": "^7.17.12"
+        "@babel/traverse": "^7.18.0",
+        "@babel/types": "^7.18.0"
       }
     },
     "@babel/helper-simple-access": {
       "dev": true
     },
     "@babel/helpers": {
-      "version": "7.17.9",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz",
-      "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.0.tgz",
+      "integrity": "sha512-AE+HMYhmlMIbho9nbvicHyxFwhrO+xhKB6AhRxzl8w46Yj0VXTZjEsAoBVC7rB2I0jzX+yWyVybnO08qkfx6kg==",
       "dev": true,
       "requires": {
         "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.9",
-        "@babel/types": "^7.17.0"
+        "@babel/traverse": "^7.18.0",
+        "@babel/types": "^7.18.0"
       }
     },
     "@babel/highlight": {
       }
     },
     "@babel/parser": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.12.tgz",
-      "integrity": "sha512-FLzHmN9V3AJIrWfOpvRlZCeVg/WLdicSnTMsLur6uDj9TT8ymUlG9XxURdW/XvuygK+2CW0poOJABdA4m/YKxA==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.0.tgz",
+      "integrity": "sha512-AqDccGC+m5O/iUStSJy3DGRIUFu7WbY/CppZYwrEUB4N0tZlnI8CSTsgL7v5fHVFmUbRv2sd+yy27o8Ydt4MGg==",
       "dev": true
     },
     "@babel/template": {
       }
     },
     "@babel/traverse": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.12.tgz",
-      "integrity": "sha512-zULPs+TbCvOkIFd4FrG53xrpxvCBwLIgo6tO0tJorY7YV2IWFxUfS/lXDJbGgfyYt9ery/Gxj2niwttNnB0gIw==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.0.tgz",
+      "integrity": "sha512-oNOO4vaoIQoGjDQ84LgtF/IAlxlyqL4TUuoQ7xLkQETFaHkY1F7yazhB4Kt3VcZGL0ZF/jhrEpnXqUb0M7V3sw==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.16.7",
-        "@babel/generator": "^7.17.12",
+        "@babel/generator": "^7.18.0",
         "@babel/helper-environment-visitor": "^7.16.7",
         "@babel/helper-function-name": "^7.17.9",
         "@babel/helper-hoist-variables": "^7.16.7",
         "@babel/helper-split-export-declaration": "^7.16.7",
-        "@babel/parser": "^7.17.12",
-        "@babel/types": "^7.17.12",
+        "@babel/parser": "^7.18.0",
+        "@babel/types": "^7.18.0",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       },
       }
     },
     "@babel/types": {
-      "version": "7.17.12",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.12.tgz",
-      "integrity": "sha512-rH8i29wcZ6x9xjzI5ILHL/yZkbQnCERdHlogKuIb4PUr7do4iT8DPekrTbBLWTnRQm6U0GYABbTMSzijmEqlAg==",
+      "version": "7.18.0",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.0.tgz",
+      "integrity": "sha512-vhAmLPAiC8j9K2GnsnLPCIH5wCrPpYIVBCWRBFDCB7Y/BXLqi/O+1RSTTM2bsmg6U/551+FCf9PNPxjABmxHTw==",
       "dev": true,
       "requires": {
         "@babel/helper-validator-identifier": "^7.16.7",
       "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
       "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="
     },
-    "@cspotcode/source-map-consumer": {
-      "version": "0.8.0",
-      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
-      "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
-      "dev": true
-    },
     "@cspotcode/source-map-support": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
-      "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+      "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
       "dev": true,
       "requires": {
-        "@cspotcode/source-map-consumer": "0.8.0"
+        "@jridgewell/trace-mapping": "0.3.9"
       }
     },
     "@dabh/diagnostics": {
       }
     },
     "@es-joy/jsdoccomment": {
-      "version": "0.29.0",
-      "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.29.0.tgz",
-      "integrity": "sha512-4yKy5t+/joLihG+ei6CCU6sc08sjUdEdXCQ2U+9h9VP13EiqHQ4YMgDC18ys/AsLdJDBX3KRx/AWY6PR7hn52Q==",
+      "version": "0.31.0",
+      "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz",
+      "integrity": "sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ==",
       "dev": true,
       "requires": {
         "comment-parser": "1.3.1",
         "esquery": "^1.4.0",
-        "jsdoc-type-pratt-parser": "~3.0.1"
+        "jsdoc-type-pratt-parser": "~3.1.0"
       }
     },
     "@eslint/eslintrc": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz",
-      "integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==",
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
+      "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
       "dev": true,
       "requires": {
         "ajv": "^6.12.4",
         "debug": "^4.3.2",
         "espree": "^9.3.2",
-        "globals": "^13.9.0",
+        "globals": "^13.15.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.2.1",
         "js-yaml": "^4.1.0",
       "dev": true
     },
     "@jridgewell/trace-mapping": {
-      "version": "0.3.13",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz",
-      "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==",
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+      "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
       "dev": true,
       "requires": {
         "@jridgewell/resolve-uri": "^3.0.3",
       }
     },
     "@mdn/browser-compat-data": {
-      "version": "4.1.20",
-      "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-4.1.20.tgz",
-      "integrity": "sha512-9VOi5TU0xE/XhShmGQpNAa3PduouSxDrEK0p7mVZe4ndhH8xV87fYb3vyYyL8i4wyRT7fHG8vyecVTRMLy04Mg==",
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-4.2.1.tgz",
+      "integrity": "sha512-EWUguj2kd7ldmrF9F+vI5hUOralPd+sdsUnYbRy33vZTuZkduC1shE9TtEMEjAQwyfyMb4ole5KtjF8MsnQOlA==",
       "dev": true
     },
     "@mikro-orm/cli": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-5.1.3.tgz",
-      "integrity": "sha512-GNAVg0hjdQrvkEvzIdec3LafocLHSZkojA+699LMoSgH9YrtOQnk/luBssdJSTJgHngb2twWlM6KCLjFSzIV5Q==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-5.1.4.tgz",
+      "integrity": "sha512-5x8B4pmyogqnp2fuulx5WD7Y2SqHEpOj67VQzkRXKUFJXDfMel2Ydp7HrknrJwn0dumB5H/MoIBLQ/Y9qFDoVg==",
       "dev": true,
       "requires": {
-        "@mikro-orm/core": "^5.1.3",
-        "@mikro-orm/knex": "^5.1.3",
+        "@mikro-orm/core": "^5.1.4",
+        "@mikro-orm/knex": "^5.1.4",
         "fs-extra": "10.1.0",
-        "tsconfig-paths": "3.14.1",
+        "tsconfig-paths": "4.0.0",
         "yargonaut": "1.1.4",
         "yargs": "15.4.1"
       }
     },
     "@mikro-orm/core": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-5.1.3.tgz",
-      "integrity": "sha512-N10ejP9EraJ5icnfjjR5v+8X5VE6fu31W5R3gi6Gd/FOsqUmUx2KEGTEA6j4f6PDstX1tKCyo9G+98LfNwmr4A==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-5.1.4.tgz",
+      "integrity": "sha512-D/nIjjAAehPQ0g51iDJrp6XS+KEfza349H2ykOd2Hztf/PnuYE5z+2HrVrAp/5GxF1Be0kD/E1CPHGFoNQMvsA==",
       "requires": {
-        "dotenv": "16.0.0",
+        "dotenv": "16.0.1",
         "escaya": "0.0.61",
         "fs-extra": "10.1.0",
         "globby": "11.0.4",
-        "mikro-orm": "^5.1.2",
+        "mikro-orm": "^5.1.4",
         "reflect-metadata": "0.1.13"
       }
     },
     "@mikro-orm/knex": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-5.1.3.tgz",
-      "integrity": "sha512-wBJsvETrx6NIdThBrrUk49kLrPY1PyL9R+su9D3b/oIfdB2W3m+KaUu8ybju0rB2K26giWNONtbyd9eKd8PrIw==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-5.1.4.tgz",
+      "integrity": "sha512-5+E4E/Hn+SfuKOSBfCaOnmAmr1ZOtRw5XWtpKdo8u1GoHQZlnu7Pv45BEbjlTDpKnumIBx4bJYsXNMXyGypOBQ==",
       "requires": {
         "fs-extra": "10.1.0",
         "knex": "2.0.0",
       }
     },
     "@mikro-orm/mariadb": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/mariadb/-/mariadb-5.1.3.tgz",
-      "integrity": "sha512-eXt4HaLJnI2mgb9EUlvfFgtW2WkKojcp07+8d/3LVyuhHqGQ8+JwOqMWHoGopoqSwtAp1E8iT+kCfHeU8xOBkw==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/mariadb/-/mariadb-5.1.4.tgz",
+      "integrity": "sha512-Z3ZJUfDeDHmUSj18K4tltdcj0fZRZ/ojRKtD13OVpEdnKneztdh/gTAJIXS40b7FMb3rVDY+Xq5Cpp1mPWVAzQ==",
       "requires": {
-        "@mikro-orm/knex": "^5.1.3",
+        "@mikro-orm/knex": "^5.1.4",
         "mariadb": "2.5.6"
       }
     },
     "@mikro-orm/reflection": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-5.1.3.tgz",
-      "integrity": "sha512-PlWMuEpY3Y7DmITENtG12kiOvkZUa3j6+J/YfA+WyRwZVyBSbWG5haHBcglbMzA0pe22IT/BX47eQd7IGXfosQ==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-5.1.4.tgz",
+      "integrity": "sha512-/w0sehByYsEmE1rX6yPzXCAjqmq62Zo7soiJN9AchMAJOzuXWlmyQ7gDfGVsx8ojglOSkij0n4u6VKogxIwZeg==",
       "requires": {
         "globby": "11.0.4",
         "ts-morph": "14.0.0"
       }
     },
     "@mikro-orm/sqlite": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/@mikro-orm/sqlite/-/sqlite-5.1.3.tgz",
-      "integrity": "sha512-/QQXxFdjQogdUxDL7RZ+V0Qj5tCFCnXBAsaRtsvcxPgwEEhdmSYydKV8xtCT5O9VJCOOFCsbwvag02l3dOLtKA==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@mikro-orm/sqlite/-/sqlite-5.1.4.tgz",
+      "integrity": "sha512-xijE6amwHIbKyVdPhXpM+wD1hzgBGdx1UCPs8pu8tMBrCtLLNJTOq7odA5SEtx0Er9dfv3I9RkPz1DGC3lzsaQ==",
       "requires": {
-        "@mikro-orm/knex": "^5.1.3",
+        "@mikro-orm/knex": "^5.1.4",
         "fs-extra": "10.1.0",
-        "sqlite3": "5.0.5",
+        "sqlite3": "5.0.8",
         "sqlstring-sqlite": "0.1.1"
       }
     },
       }
     },
     "@tensorflow/tfjs-backend-cpu": {
-      "version": "3.17.0",
-      "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.17.0.tgz",
-      "integrity": "sha512-alfmaPLnsa/DvkhnPoX/r9ZVDcSuRZUJEElaG3o84JrCBOqzq2jcFwaT9KxchN8rDLmKjJMLQkcQx/bSp/Oz4w==",
+      "version": "3.18.0",
+      "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.18.0.tgz",
+      "integrity": "sha512-LcSqlylzGtpgngcMFIL3q9Q3eVaPRJ7ITZt7ivhzkCj4R5ZsnPa9qM3DCVihkQ77heAwSw4hPTo2jp5C4mJ4Cg==",
       "dev": true,
       "requires": {
         "@types/seedrandom": "2.4.27",
       }
     },
     "@tensorflow/tfjs-core": {
-      "version": "3.17.0",
-      "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-3.17.0.tgz",
-      "integrity": "sha512-PMqEDysVy3WsSK4pU+UaoINRjps1RTF2CPvS1sWgOJqc/rUz8mSMibMosti0Is6DHGw7UiAq53y9VMuzQRVJqA==",
+      "version": "3.18.0",
+      "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-3.18.0.tgz",
+      "integrity": "sha512-gMxisZozqsr5sCKlphF/eVBLg91MjlBiN60tjX8hJAu0WlSn6Gi5k65GNIL+Pq6hrxpvImcfdCmTH/2XJVZ0Mg==",
       "dev": true,
       "requires": {
         "@types/long": "^4.0.1",
       }
     },
     "@types/node": {
-      "version": "16.11.35",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.35.tgz",
-      "integrity": "sha512-QXu45LyepgnhUfnIAj/FyT4uM87ug5KpIrgXfQtUPNAlx8w5hmd8z8emqCLNvG11QkpRSCG9Qg2buMxvqfjfsQ=="
+      "version": "16.11.36",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.36.tgz",
+      "integrity": "sha512-FR5QJe+TaoZ2GsMHkjuwoNabr+UrJNRr2HNOo+r/7vhcuntM6Ee/pRPOnRhhL2XE9OOvX9VLEq+BcXl3VjNoWA=="
     },
     "@types/object-path": {
       "version": "0.11.1",
       "dev": true
     },
     "@typescript-eslint/eslint-plugin": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.24.0.tgz",
-      "integrity": "sha512-6bqFGk6wa9+6RrU++eLknKyDqXU1Oc8nyoLu5a1fU17PNRJd9UBr56rMF7c4DRaRtnarlkQ4jwxUbvBo8cNlpw==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.26.0.tgz",
+      "integrity": "sha512-oGCmo0PqnRZZndr+KwvvAUvD3kNE4AfyoGCwOZpoCncSh4MVD06JTE8XQa2u9u+NX5CsyZMBTEc2C72zx38eYA==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/scope-manager": "5.24.0",
-        "@typescript-eslint/type-utils": "5.24.0",
-        "@typescript-eslint/utils": "5.24.0",
+        "@typescript-eslint/scope-manager": "5.26.0",
+        "@typescript-eslint/type-utils": "5.26.0",
+        "@typescript-eslint/utils": "5.26.0",
         "debug": "^4.3.4",
         "functional-red-black-tree": "^1.0.1",
         "ignore": "^5.2.0",
       }
     },
     "@typescript-eslint/parser": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.24.0.tgz",
-      "integrity": "sha512-4q29C6xFYZ5B2CXqSBBdcS0lPyfM9M09DoQLtHS5kf+WbpV8pBBhHDLNhXfgyVwFnhrhYzOu7xmg02DzxeF2Uw==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.26.0.tgz",
+      "integrity": "sha512-n/IzU87ttzIdnAH5vQ4BBDnLPly7rC5VnjN3m0xBG82HK6rhRxnCb3w/GyWbNDghPd+NktJqB/wl6+YkzZ5T5Q==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/scope-manager": "5.24.0",
-        "@typescript-eslint/types": "5.24.0",
-        "@typescript-eslint/typescript-estree": "5.24.0",
+        "@typescript-eslint/scope-manager": "5.26.0",
+        "@typescript-eslint/types": "5.26.0",
+        "@typescript-eslint/typescript-estree": "5.26.0",
         "debug": "^4.3.4"
       }
     },
     "@typescript-eslint/scope-manager": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.24.0.tgz",
-      "integrity": "sha512-WpMWipcDzGmMzdT7NtTjRXFabx10WleLUGrJpuJLGaxSqpcyq5ACpKSD5VE40h2nz3melQ91aP4Du7lh9FliCA==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.26.0.tgz",
+      "integrity": "sha512-gVzTJUESuTwiju/7NiTb4c5oqod8xt5GhMbExKsCTp6adU3mya6AGJ4Pl9xC7x2DX9UYFsjImC0mA62BCY22Iw==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "5.24.0",
-        "@typescript-eslint/visitor-keys": "5.24.0"
+        "@typescript-eslint/types": "5.26.0",
+        "@typescript-eslint/visitor-keys": "5.26.0"
       }
     },
     "@typescript-eslint/type-utils": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.24.0.tgz",
-      "integrity": "sha512-uGi+sQiM6E5CeCZYBXiaIvIChBXru4LZ1tMoeKbh1Lze+8BO9syUG07594C4lvN2YPT4KVeIupOJkVI+9/DAmQ==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.26.0.tgz",
+      "integrity": "sha512-7ccbUVWGLmcRDSA1+ADkDBl5fP87EJt0fnijsMFTVHXKGduYMgienC/i3QwoVhDADUAPoytgjbZbCOMj4TY55A==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/utils": "5.24.0",
+        "@typescript-eslint/utils": "5.26.0",
         "debug": "^4.3.4",
         "tsutils": "^3.21.0"
       }
     },
     "@typescript-eslint/types": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.24.0.tgz",
-      "integrity": "sha512-Tpg1c3shTDgTmZd3qdUyd+16r/pGmVaVEbLs+ufuWP0EruVbUiEOmpBBQxBb9a8iPRxi8Rb2oiwOxuZJzSq11A==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.26.0.tgz",
+      "integrity": "sha512-8794JZFE1RN4XaExLWLI2oSXsVImNkl79PzTOOWt9h0UHROwJedNOD2IJyfL0NbddFllcktGIO2aOu10avQQyA==",
       "dev": true
     },
     "@typescript-eslint/typescript-estree": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.24.0.tgz",
-      "integrity": "sha512-zcor6vQkQmZAQfebSPVwUk/FD+CvnsnlfKXYeQDsWXRF+t7SBPmIfNia/wQxCSeu1h1JIjwV2i9f5/DdSp/uDw==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.26.0.tgz",
+      "integrity": "sha512-EyGpw6eQDsfD6jIqmXP3rU5oHScZ51tL/cZgFbFBvWuCwrIptl+oueUZzSmLtxFuSOQ9vDcJIs+279gnJkfd1w==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "5.24.0",
-        "@typescript-eslint/visitor-keys": "5.24.0",
+        "@typescript-eslint/types": "5.26.0",
+        "@typescript-eslint/visitor-keys": "5.26.0",
         "debug": "^4.3.4",
         "globby": "^11.1.0",
         "is-glob": "^4.0.3",
       }
     },
     "@typescript-eslint/utils": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.24.0.tgz",
-      "integrity": "sha512-K05sbWoeCBJH8KXu6hetBJ+ukG0k2u2KlgD3bN+v+oBKm8adJqVHpSSLHNzqyuv0Lh4GVSAUgZ5lB4icmPmWLw==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.26.0.tgz",
+      "integrity": "sha512-PJFwcTq2Pt4AMOKfe3zQOdez6InIDOjUJJD3v3LyEtxHGVVRK3Vo7Dd923t/4M9hSH2q2CLvcTdxlLPjcIk3eg==",
       "dev": true,
       "requires": {
         "@types/json-schema": "^7.0.9",
-        "@typescript-eslint/scope-manager": "5.24.0",
-        "@typescript-eslint/types": "5.24.0",
-        "@typescript-eslint/typescript-estree": "5.24.0",
+        "@typescript-eslint/scope-manager": "5.26.0",
+        "@typescript-eslint/types": "5.26.0",
+        "@typescript-eslint/typescript-estree": "5.26.0",
         "eslint-scope": "^5.1.1",
         "eslint-utils": "^3.0.0"
       }
     },
     "@typescript-eslint/visitor-keys": {
-      "version": "5.24.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.24.0.tgz",
-      "integrity": "sha512-qzGwSXMyMnogcAo+/2fU+jhlPPVMXlIH2PeAonIKjJSoDKl1+lJVvG5Z5Oud36yU0TWK2cs1p/FaSN5J2OUFYA==",
+      "version": "5.26.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.26.0.tgz",
+      "integrity": "sha512-wei+ffqHanYDOQgg/fS6Hcar6wAWv0CUPQ3TZzOWd2BLfgP539rb49bwua8WRAs7R6kOSLn82rfEu2ro6Llt8Q==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "5.24.0",
+        "@typescript-eslint/types": "5.26.0",
         "eslint-visitor-keys": "^3.3.0"
       }
     },
       "dev": true
     },
     "@webgpu/types": {
-      "version": "0.1.16",
-      "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.16.tgz",
-      "integrity": "sha512-9E61voMP4+Rze02jlTXud++Htpjyyk8vw5Hyw9FGRrmhHQg2GqbuOfwf5Klrb8vTxc2XWI3EfO7RUHMpxTj26A==",
+      "version": "0.1.17",
+      "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.17.tgz",
+      "integrity": "sha512-M8INbXsMdkWtVsSHRPEiTXHe0S4gxMhYA/Kz4pNoUF9IXd3PHMi6/2n8EAsqkAEdna+aeCm2RmscWV0hsmIf0Q==",
       "dev": true
     },
     "@wessberg/stringutil": {
       }
     },
     "bn.js": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
-      "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==",
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+      "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
       "dev": true
     },
     "body-parser": {
       }
     },
     "bson": {
-      "version": "4.6.3",
-      "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.3.tgz",
-      "integrity": "sha512-rAqP5hcUVJhXP2MCSNVsf0oM2OGU1So6A9pVRDYayvJ5+hygXHQApf87wd5NlhPM1J9RJnbqxIG/f8QTzRoQ4A==",
+      "version": "4.6.4",
+      "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.4.tgz",
+      "integrity": "sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ==",
       "requires": {
         "buffer": "^5.6.0"
       },
       "dev": true
     },
     "caniuse-lite": {
-      "version": "1.0.30001341",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz",
-      "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==",
+      "version": "1.0.30001342",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001342.tgz",
+      "integrity": "sha512-bn6sOCu7L7jcbBbyNhLg0qzXdJ/PMbybZTH/BA6Roet9wxYRm6Tr9D0s0uhLkOZ6MSG+QU6txUgdpr3MXIVqjA==",
       "dev": true
     },
     "caseless": {
       }
     },
     "dotenv": {
-      "version": "16.0.0",
-      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz",
-      "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q=="
+      "version": "16.0.1",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz",
+      "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ=="
     },
     "dup": {
       "version": "1.0.0",
       }
     },
     "es-abstract": {
-      "version": "1.20.0",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.0.tgz",
-      "integrity": "sha512-URbD8tgRthKD3YcC39vbvSDrX23upXnPcnGAjQfgxXF5ID75YcENawc9ZX/9iTP9ptUyfCLIxTTuMYoRfiOVKA==",
+      "version": "1.20.1",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz",
+      "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==",
       "dev": true,
       "requires": {
         "call-bind": "^1.0.2",
         "object-inspect": "^1.12.0",
         "object-keys": "^1.1.1",
         "object.assign": "^4.1.2",
-        "regexp.prototype.flags": "^1.4.1",
+        "regexp.prototype.flags": "^1.4.3",
         "string.prototype.trimend": "^1.0.5",
         "string.prototype.trimstart": "^1.0.5",
         "unbox-primitive": "^1.0.2"
       }
     },
     "eslint": {
-      "version": "8.15.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz",
-      "integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==",
+      "version": "8.16.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz",
+      "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==",
       "dev": true,
       "requires": {
-        "@eslint/eslintrc": "^1.2.3",
+        "@eslint/eslintrc": "^1.3.0",
         "@humanwhocodes/config-array": "^0.9.2",
         "ajv": "^6.10.0",
         "chalk": "^4.0.0",
         "file-entry-cache": "^6.0.1",
         "functional-red-black-tree": "^1.0.1",
         "glob-parent": "^6.0.1",
-        "globals": "^13.6.0",
+        "globals": "^13.15.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.0.0",
         "imurmurhash": "^0.1.4",
             "esutils": "^2.0.2"
           }
         },
+        "json5": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+          "dev": true,
+          "requires": {
+            "minimist": "^1.2.0"
+          }
+        },
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
           "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
           "dev": true
+        },
+        "strip-bom": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+          "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+          "dev": true
+        },
+        "tsconfig-paths": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
+          "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
+          "dev": true,
+          "requires": {
+            "@types/json5": "^0.0.29",
+            "json5": "^1.0.1",
+            "minimist": "^1.2.6",
+            "strip-bom": "^3.0.0"
+          }
         }
       }
     },
     "eslint-plugin-jsdoc": {
-      "version": "39.2.9",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.2.9.tgz",
-      "integrity": "sha512-gaPYJT94rWlWyQcisQyyEJHtLaaJqN4baFlLCEr/LcXVibS9wzQTL2dskqk327ggwqQopR+Xecu2Lng1IJ9Ypw==",
+      "version": "39.3.2",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.2.tgz",
+      "integrity": "sha512-RSGN94RYzIJS/WfW3l6cXzRLfJWxvJgNQZ4w0WCaxJWDJMigtwTsILEAfKqmmPkT2rwMH/s3C7G5ChDE6cwPJg==",
       "dev": true,
       "requires": {
-        "@es-joy/jsdoccomment": "~0.29.0",
+        "@es-joy/jsdoccomment": "~0.31.0",
         "comment-parser": "1.3.1",
         "debug": "^4.3.4",
         "escape-string-regexp": "^4.0.0",
       "dev": true
     },
     "jsdoc-type-pratt-parser": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.0.1.tgz",
-      "integrity": "sha512-vqMCdAFVIiFhVgBYE/X8naf3L/7qiJsaYWTfUJZZZ124dR3OUz9HrmaMUGpYIYAN4VSuodf6gIZY0e8ktPw9cg==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz",
+      "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==",
       "dev": true
     },
     "jsesc": {
       }
     },
     "keyv": {
-      "version": "4.2.8",
-      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.2.8.tgz",
-      "integrity": "sha512-IZZo6krhHWPhgsP5mBkEdPopVPN/stgCnBVuqi6dda/Nm5mDTOSVTrFMkWqlJsDum+B0YSe887tNxdjDWkO7aQ==",
+      "version": "4.2.9",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.2.9.tgz",
+      "integrity": "sha512-vqRBrN4xQHud7UMAGzGGFbt96MtGB9pb0OOg8Dhtq5RtiswCb1pCFq878iqC4hdeOP6eDPnCoFxA+2TXx427Ow==",
       "dev": true,
       "requires": {
         "compress-brotli": "^1.3.8",
       },
       "dependencies": {
         "@types/node": {
-          "version": "17.0.33",
-          "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.33.tgz",
-          "integrity": "sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ=="
+          "version": "17.0.35",
+          "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz",
+          "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg=="
         },
         "iconv-lite": {
           "version": "0.6.3",
       }
     },
     "mikro-orm": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-5.1.2.tgz",
-      "integrity": "sha512-Qyy+EZeBRiyzLstX9Ug9vyDvmz9SIgK4g/h4oMSjgv/VyMwboUuIi4NSXc8HqrpolTdotmcsEzM3d23DUZYSsQ=="
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-5.1.4.tgz",
+      "integrity": "sha512-etO+2eooBMf/dHJmLbnRsk9P8rf9oYJn1lJ13gEUuBUE7+Rqs7XXqGMR2AFiEbhLU1ZxH58rWOODLZd5zl+V7g=="
     },
     "miller-rabin": {
       "version": "4.0.1",
       "integrity": "sha512-VoAYUqmPRmzKbbqRejjqceGFp3VF81Qe8XXFGU0UXLxB7Mf4GGvyGq5Qn3k4AiQgDEV6WzobqlPOd+j0+m6IrA==",
       "dev": true
     },
+    "mnemonist": {
+      "version": "0.39.1",
+      "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.1.tgz",
+      "integrity": "sha512-bY13FSvcbKLj+FaJcR2+xFZ3m2R1+BrLpavAh0BMyGSq0iPowbvYllwitlkvVyEowEYSulCMzxDaju9bC4+cow==",
+      "requires": {
+        "obliterator": "^2.0.1"
+      }
+    },
     "mocha": {
       "version": "10.0.0",
       "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz",
       }
     },
     "node-releases": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz",
-      "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz",
+      "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==",
       "dev": true
     },
     "nopt": {
       "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw=="
     },
     "object-inspect": {
-      "version": "1.12.0",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
-      "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g=="
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.1.tgz",
+      "integrity": "sha512-Y/jF6vnvEtOPGiKD1+q+X0CiUYRQtEHp89MLLUJ7TUivtH8Ugn2+3A7Rynqk7BRsAoqeOQWnFnjpDrKSxDgIGA=="
     },
     "object-keys": {
       "version": "1.1.1",
         "es-abstract": "^1.19.1"
       }
     },
+    "obliterator": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz",
+      "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ=="
+    },
     "on-finished": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
       "integrity": "sha512-bzthEM2MRwt4mDVC7sWYBRu7pTpb+aDj+Bw2EhoxtYTSL6wbWTu94gW7wuTwjCPClNRDiCPxV5bHQz5X/M/PnA=="
     },
     "postcss": {
-      "version": "8.4.13",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.13.tgz",
-      "integrity": "sha512-jtL6eTBrza5MPzy8oJLFuUscHDXTV5KcLlqAWHl5q5WYRfnNRGSmOZmOZ1T6Gy7A99mOZfqungmZMpMmCVJ8ZA==",
+      "version": "8.4.14",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
+      "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
       "dev": true,
       "requires": {
-        "nanoid": "^3.3.3",
+        "nanoid": "^3.3.4",
         "picocolors": "^1.0.0",
         "source-map-js": "^1.0.2"
+      },
+      "dependencies": {
+        "nanoid": {
+          "version": "3.3.4",
+          "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
+          "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
+          "dev": true
+        }
       }
     },
     "postcss-import": {
       }
     },
     "rollup": {
-      "version": "2.73.0",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.73.0.tgz",
-      "integrity": "sha512-h/UngC3S4Zt28mB3g0+2YCMegT5yoftnQplwzPqGZcKvlld5e+kT/QRmJiL+qxGyZKOYpgirWGdLyEO1b0dpLQ==",
+      "version": "2.74.1",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.74.1.tgz",
+      "integrity": "sha512-K2zW7kV8Voua5eGkbnBtWYfMIhYhT9Pel2uhBk2WO5eMee161nPze/XRfvEQPFYz7KgrCCnmh2Wy0AMFLGGmMA==",
       "dev": true,
       "requires": {
         "fsevents": "~2.3.2"
       "dev": true
     },
     "sqlite3": {
-      "version": "5.0.5",
-      "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.5.tgz",
-      "integrity": "sha512-ZZFOMW31IOMbUeSiL23TuWSjNyS7Z83EDJ80HJxCe78OZ+5BJT6IhAwAUnQgPsUl5z+Er0DGx7VjuTP7PKPNcg==",
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.8.tgz",
+      "integrity": "sha512-f2ACsbSyb2D1qFFcqIXPfFscLtPVOWJr5GmUzYxf4W+0qelu5MWrR+FAQE1d5IUArEltBrzSDxDORG8P/IkqyQ==",
       "requires": {
         "@mapbox/node-pre-gyp": "^1.0.0",
         "node-addon-api": "^4.2.0",
       }
     },
     "ts-node": {
-      "version": "10.7.0",
-      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz",
-      "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==",
+      "version": "10.8.0",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.0.tgz",
+      "integrity": "sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==",
       "dev": true,
       "requires": {
-        "@cspotcode/source-map-support": "0.7.0",
+        "@cspotcode/source-map-support": "^0.8.0",
         "@tsconfig/node10": "^1.0.7",
         "@tsconfig/node12": "^1.0.7",
         "@tsconfig/node14": "^1.0.0",
         "create-require": "^1.1.0",
         "diff": "^4.0.1",
         "make-error": "^1.1.1",
-        "v8-compile-cache-lib": "^3.0.0",
+        "v8-compile-cache-lib": "^3.0.1",
         "yn": "3.1.1"
       },
       "dependencies": {
       }
     },
     "tsconfig-paths": {
-      "version": "3.14.1",
-      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
-      "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.0.0.tgz",
+      "integrity": "sha512-SLBg2GBKlR6bVtMgJJlud/o3waplKtL7skmLkExomIiaAtLGtVsoXIqP3SYdjbcH9lq/KVv7pMZeCBpLYOit6Q==",
       "dev": true,
       "requires": {
-        "@types/json5": "^0.0.29",
-        "json5": "^1.0.1",
+        "json5": "^2.2.1",
         "minimist": "^1.2.6",
         "strip-bom": "^3.0.0"
       },
       "dependencies": {
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
         "strip-bom": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
index 6d361e7945b0abef4aa67ecda4fb0b950573f086..629854eb78e52e840e585e6ecfe01c184af8eccd 100644 (file)
     "release": "release-it"
   },
   "dependencies": {
-    "@mikro-orm/core": "^5.1.3",
-    "@mikro-orm/mariadb": "^5.1.3",
-    "@mikro-orm/reflection": "^5.1.3",
-    "@mikro-orm/sqlite": "^5.1.3",
+    "@mikro-orm/core": "^5.1.4",
+    "@mikro-orm/mariadb": "^5.1.4",
+    "@mikro-orm/reflection": "^5.1.4",
+    "@mikro-orm/sqlite": "^5.1.4",
     "basic-ftp": "^4.6.6",
     "chalk": "^4.1.2",
     "express": "^4.18.1",
+    "mnemonist": "^0.39.1",
     "moment": "^2.29.3",
     "mongodb": "^4.6.0",
     "poolifier": "^2.2.0",
   },
   "devDependencies": {
     "@istanbuljs/nyc-config-typescript": "^1.0.2",
-    "@mikro-orm/cli": "^5.1.3",
+    "@mikro-orm/cli": "^5.1.4",
     "@rollup/plugin-json": "^4.1.0",
     "@types/express": "^4.17.13",
     "@types/mocha": "^9.1.1",
     "@types/mochawesome": "^6.2.1",
-    "@types/node": "^16.11.35",
+    "@types/node": "^16.11.36",
     "@types/proper-lockfile": "^4.1.2",
     "@types/tar": "^6.1.1",
     "@types/uuid": "^8.3.4",
     "@types/ws": "^8.5.3",
-    "@typescript-eslint/eslint-plugin": "^5.24.0",
-    "@typescript-eslint/parser": "^5.24.0",
+    "@typescript-eslint/eslint-plugin": "^5.26.0",
+    "@typescript-eslint/parser": "^5.26.0",
     "auto-changelog": "^2.4.0",
     "clinic": "^11.1.0",
     "cross-env": "^7.0.3",
-    "eslint": "^8.15.0",
+    "eslint": "^8.16.0",
     "eslint-config-prettier": "^8.5.0",
     "eslint-plugin-import": "^2.26.0",
-    "eslint-plugin-jsdoc": "^39.2.9",
+    "eslint-plugin-jsdoc": "^39.3.2",
     "eslint-plugin-node": "^11.1.0",
     "eslint-plugin-prettier": "^4.0.0",
     "expect": "^28.1.0",
     "prettier": "^2.6.2",
     "release-it": "^15.0.0",
     "robohydra": "^0.6.9",
-    "rollup": "^2.73.0",
+    "rollup": "^2.74.1",
     "rollup-plugin-analyzer": "^4.0.0",
     "rollup-plugin-copy": "^3.4.0",
     "rollup-plugin-delete": "^2.0.0",
     "rollup-plugin-istanbul": "^3.0.0",
     "rollup-plugin-terser": "^7.0.2",
     "rollup-plugin-ts": "^2.0.7",
-    "ts-node": "^10.7.0",
+    "ts-node": "^10.8.0",
     "typescript": "^4.6.4"
   }
 }
index 0cc0ef5b1d088b7e148b7e476be77c389e7ca7a6..be738ef7d947b67444b9f261c66cd10d5db90d69 100644 (file)
@@ -27,6 +27,7 @@ export default {
     'fs',
     '@mikro-orm/core',
     '@mikro-orm/reflection',
+    'mnemonist/lru-map-with-delete',
     'moment',
     'mongodb',
     'path',
index 54fcb6dba0712bd75bf485ac5774c22ccb493fc2..211cf02079230624a525dc92d4a26e2d9cb904ca 100644 (file)
@@ -29,7 +29,8 @@ export default class Bootstrap {
   private workerImplementation: WorkerAbstract<ChargingStationWorkerData> | null = null;
   private readonly uiServer!: AbstractUIServer;
   private readonly storage!: Storage;
-  private numberOfChargingStations: number;
+  private numberOfChargingStationTemplates!: number;
+  private numberOfChargingStations!: number;
   private readonly version: string = version;
   private started: boolean;
   private readonly workerScript: string;
@@ -41,6 +42,7 @@ export default class Bootstrap {
       'charging-station',
       'ChargingStationWorker.js'
     );
+    this.initialize();
     this.initWorkerImplementation();
     Configuration.getUIServer().enabled &&
       (this.uiServer = UIServerFactory.getUIServerImplementation(ApplicationProtocol.WS, {
@@ -66,11 +68,12 @@ export default class Bootstrap {
   public async start(): Promise<void> {
     if (isMainThread && !this.started) {
       try {
-        this.numberOfChargingStations = 0;
+        this.initialize();
         await this.storage?.open();
         await this.workerImplementation.start();
         this.uiServer?.start();
         const stationTemplateUrls = Configuration.getStationTemplateUrls();
+        this.numberOfChargingStationTemplates = stationTemplateUrls.length;
         // Start ChargingStation object in worker thread
         if (stationTemplateUrls) {
           for (const stationTemplateUrl of stationTemplateUrls) {
@@ -102,7 +105,7 @@ export default class Bootstrap {
             chalk.green(
               `Charging stations simulator ${
                 this.version
-              } started with ${this.numberOfChargingStations.toString()} charging station(s) and ${
+              } started with ${this.numberOfChargingStations.toString()} charging station(s) from ${this.numberOfChargingStationTemplates.toString()} configured charging station template(s) and ${
                 ChargingStationUtils.workerDynamicPoolInUse()
                   ? `${Configuration.getWorkerPoolMinSize().toString()}/`
                   : ''
@@ -140,6 +143,7 @@ export default class Bootstrap {
 
   public async restart(): Promise<void> {
     await this.stop();
+    this.initialize();
     this.initWorkerImplementation();
     await this.start();
   }
@@ -170,6 +174,11 @@ export default class Bootstrap {
     );
   }
 
+  private initialize() {
+    this.numberOfChargingStations = 0;
+    this.numberOfChargingStationTemplates = 0;
+  }
+
   private async startChargingStation(
     index: number,
     stationTemplateUrl: StationTemplateUrl
index 064e33ad805a19ac5063d8175e5747c9bda88689..6e9a0d874080dd6f87fc1b12c1dcf1494dd826b4 100644 (file)
@@ -22,7 +22,6 @@ import {
   StatusNotificationResponse,
 } from '../types/ocpp/Responses';
 import { ChargingProfile, ChargingRateUnitType } from '../types/ocpp/ChargingProfile';
-import ChargingStationConfiguration, { Section } from '../types/ChargingStationConfiguration';
 import ChargingStationTemplate, {
   CurrentType,
   PowerUnits,
@@ -48,6 +47,8 @@ import { AutomaticTransactionGeneratorConfiguration } from '../types/AutomaticTr
 import BaseError from '../exception/BaseError';
 import { ChargePointErrorCode } from '../types/ocpp/ChargePointErrorCode';
 import { ChargePointStatus } from '../types/ocpp/ChargePointStatus';
+import { ChargingStationCache } from './ChargingStationCache';
+import ChargingStationConfiguration from '../types/ChargingStationConfiguration';
 import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils';
 import ChargingStationInfo from '../types/ChargingStationInfo';
 import ChargingStationOcppConfiguration from '../types/ChargingStationOcppConfiguration';
@@ -95,6 +96,7 @@ export default class ChargingStation {
   public powerDivider!: number;
   private readonly index: number;
   private configurationFile!: string;
+  private configurationFileHash!: string;
   private bootNotificationRequest!: BootNotificationRequest;
   private connectorsConfigurationHash!: string;
   private ocppIncomingRequestService!: OCPPIncomingRequestService;
@@ -103,6 +105,7 @@ export default class ChargingStation {
   private wsConnectionRestarted: boolean;
   private autoReconnectRetryCount: number;
   private stopped: boolean;
+  private readonly cache: ChargingStationCache;
   private automaticTransactionGenerator!: AutomaticTransactionGenerator;
   private webSocketPingSetInterval!: NodeJS.Timeout;
 
@@ -112,6 +115,7 @@ export default class ChargingStation {
     this.stopped = false;
     this.wsConnectionRestarted = false;
     this.autoReconnectRetryCount = 0;
+    this.cache = ChargingStationCache.getInstance();
     this.connectors = new Map<number, ConnectorStatus>();
     this.requests = new Map<string, CachedRequest>();
     this.messageBuffer = new Set<string>();
@@ -507,6 +511,7 @@ export default class ChargingStation {
                 this.templateFile
               } file have changed, reload`
             );
+            this.cache.deleteChargingStationTemplate(this.stationInfo?.templateHash);
             // Initialize
             this.initialize();
             // Restart the ATG
@@ -555,6 +560,8 @@ export default class ChargingStation {
     if (this.getEnableStatistics()) {
       this.performanceStatistics.stop();
     }
+    this.cache.deleteChargingStationConfiguration(this.configurationFileHash);
+    this.cache.deleteChargingStationTemplate(this.stationInfo?.templateHash);
     this.bootNotificationResponse = null;
     parentPort.postMessage({
       id: ChargingStationWorkerMessageEvents.STOPPED,
@@ -572,7 +579,7 @@ export default class ChargingStation {
 
   public saveOcppConfiguration(): void {
     if (this.getOcppPersistentConfiguration()) {
-      this.saveConfiguration(Section.ocppConfiguration);
+      this.saveConfiguration();
     }
   }
 
@@ -705,14 +712,21 @@ export default class ChargingStation {
   private getTemplateFromFile(): ChargingStationTemplate | null {
     let template: ChargingStationTemplate = null;
     try {
-      const measureId = `${FileType.ChargingStationTemplate} read`;
-      const beginId = PerformanceStatistics.beginMeasure(measureId);
-      template = JSON.parse(fs.readFileSync(this.templateFile, 'utf8')) as ChargingStationTemplate;
-      PerformanceStatistics.endMeasure(measureId, beginId);
-      template.templateHash = crypto
-        .createHash(Constants.DEFAULT_HASH_ALGORITHM)
-        .update(JSON.stringify(template))
-        .digest('hex');
+      if (this.cache.hasChargingStationTemplate(this.stationInfo?.templateHash)) {
+        template = this.cache.getChargingStationTemplate(this.stationInfo.templateHash);
+      } else {
+        const measureId = `${FileType.ChargingStationTemplate} read`;
+        const beginId = PerformanceStatistics.beginMeasure(measureId);
+        template = JSON.parse(
+          fs.readFileSync(this.templateFile, 'utf8')
+        ) as ChargingStationTemplate;
+        PerformanceStatistics.endMeasure(measureId, beginId);
+        template.templateHash = crypto
+          .createHash(Constants.DEFAULT_HASH_ALGORITHM)
+          .update(JSON.stringify(template))
+          .digest('hex');
+        this.cache.setChargingStationTemplate(template);
+      }
     } catch (error) {
       FileUtils.handleFileException(
         this.logPrefix(),
@@ -837,7 +851,7 @@ export default class ChargingStation {
 
   private saveStationInfo(): void {
     if (this.getStationInfoPersistentConfiguration()) {
-      this.saveConfiguration(Section.stationInfo);
+      this.saveConfiguration();
     }
   }
 
@@ -906,7 +920,7 @@ export default class ChargingStation {
         this.handleUnsupportedVersion(this.getOcppVersion());
         break;
     }
-    if (this.stationInfo.autoRegister) {
+    if (this.stationInfo?.autoRegister) {
       this.bootNotificationResponse = {
         currentTime: new Date().toISOString(),
         interval: this.getHeartbeatInterval() / 1000,
@@ -1161,12 +1175,18 @@ export default class ChargingStation {
     let configuration: ChargingStationConfiguration = null;
     if (this.configurationFile && fs.existsSync(this.configurationFile)) {
       try {
-        const measureId = `${FileType.ChargingStationConfiguration} read`;
-        const beginId = PerformanceStatistics.beginMeasure(measureId);
-        configuration = JSON.parse(
-          fs.readFileSync(this.configurationFile, 'utf8')
-        ) as ChargingStationConfiguration;
-        PerformanceStatistics.endMeasure(measureId, beginId);
+        if (this.cache.hasChargingStationConfiguration(this.configurationFileHash)) {
+          configuration = this.cache.getChargingStationConfiguration(this.configurationFileHash);
+        } else {
+          const measureId = `${FileType.ChargingStationConfiguration} read`;
+          const beginId = PerformanceStatistics.beginMeasure(measureId);
+          configuration = JSON.parse(
+            fs.readFileSync(this.configurationFile, 'utf8')
+          ) as ChargingStationConfiguration;
+          PerformanceStatistics.endMeasure(measureId, beginId);
+          this.configurationFileHash = configuration.configurationHash;
+          this.cache.setChargingStationConfiguration(configuration);
+        }
       } catch (error) {
         FileUtils.handleFileException(
           this.logPrefix(),
@@ -1179,7 +1199,7 @@ export default class ChargingStation {
     return configuration;
   }
 
-  private saveConfiguration(section?: Section): void {
+  private saveConfiguration(): void {
     if (this.configurationFile) {
       try {
         if (!fs.existsSync(path.dirname(this.configurationFile))) {
@@ -1187,34 +1207,32 @@ export default class ChargingStation {
         }
         const configurationData: ChargingStationConfiguration =
           this.getConfigurationFromFile() ?? {};
-        switch (section) {
-          case Section.ocppConfiguration:
-            configurationData.configurationKey = this.ocppConfiguration.configurationKey;
-            break;
-          case Section.stationInfo:
-            if (configurationData?.stationInfo?.infoHash === this.stationInfo?.infoHash) {
-              logger.debug(
-                `${this.logPrefix()} Not saving unchanged charging station information to configuration file ${
-                  this.configurationFile
-                }`
-              );
-              return;
-            }
-            configurationData.stationInfo = this.stationInfo;
-            break;
-          default:
-            configurationData.configurationKey = this.ocppConfiguration.configurationKey;
-            if (configurationData?.stationInfo?.infoHash !== this.stationInfo?.infoHash) {
-              configurationData.stationInfo = this.stationInfo;
-            }
-            break;
+        this.ocppConfiguration?.configurationKey &&
+          (configurationData.configurationKey = this.ocppConfiguration.configurationKey);
+        this.stationInfo && (configurationData.stationInfo = this.stationInfo);
+        delete configurationData.configurationHash;
+        const configurationHash = crypto
+          .createHash(Constants.DEFAULT_HASH_ALGORITHM)
+          .update(JSON.stringify(configurationData))
+          .digest('hex');
+        if (this.configurationFileHash !== configurationHash) {
+          configurationData.configurationHash = configurationHash;
+          const measureId = `${FileType.ChargingStationConfiguration} write`;
+          const beginId = PerformanceStatistics.beginMeasure(measureId);
+          const fileDescriptor = fs.openSync(this.configurationFile, 'w');
+          fs.writeFileSync(fileDescriptor, JSON.stringify(configurationData, null, 2), 'utf8');
+          fs.closeSync(fileDescriptor);
+          PerformanceStatistics.endMeasure(measureId, beginId);
+          this.cache.deleteChargingStationConfiguration(this.configurationFileHash);
+          this.configurationFileHash = configurationHash;
+          this.cache.setChargingStationConfiguration(configurationData);
+        } else {
+          logger.debug(
+            `${this.logPrefix()} Not saving unchanged charging station configuration file ${
+              this.configurationFile
+            }`
+          );
         }
-        const measureId = `${FileType.ChargingStationConfiguration} write`;
-        const beginId = PerformanceStatistics.beginMeasure(measureId);
-        const fileDescriptor = fs.openSync(this.configurationFile, 'w');
-        fs.writeFileSync(fileDescriptor, JSON.stringify(configurationData, null, 2), 'utf8');
-        fs.closeSync(fileDescriptor);
-        PerformanceStatistics.endMeasure(measureId, beginId);
       } catch (error) {
         FileUtils.handleFileException(
           this.logPrefix(),
@@ -1585,7 +1603,7 @@ export default class ChargingStation {
   }
 
   private async startMessageSequence(): Promise<void> {
-    if (this.stationInfo.autoRegister) {
+    if (this.stationInfo?.autoRegister) {
       await this.ocppRequestService.requestHandler<
         BootNotificationRequest,
         BootNotificationResponse
@@ -1844,7 +1862,7 @@ export default class ChargingStation {
     if (HeartBeatInterval) {
       return Utils.convertToInt(HeartBeatInterval.value) * 1000;
     }
-    !this.stationInfo.autoRegister &&
+    !this.stationInfo?.autoRegister &&
       logger.warn(
         `${this.logPrefix()} Heartbeat interval configuration key not set, using default value: ${
           Constants.DEFAULT_HEARTBEAT_INTERVAL
diff --git a/src/charging-station/ChargingStationCache.ts b/src/charging-station/ChargingStationCache.ts
new file mode 100644 (file)
index 0000000..8aff62a
--- /dev/null
@@ -0,0 +1,95 @@
+import ChargingStationConfiguration from '../types/ChargingStationConfiguration';
+import ChargingStationTemplate from '../types/ChargingStationTemplate';
+import { ChargingStationUtils } from './ChargingStationUtils';
+import LRUCache from 'mnemonist/lru-map-with-delete';
+
+enum CacheType {
+  CHARGING_STATION_TEMPLATE = 'chargingStationTemplate',
+  CHARGING_STATION_CONFIGURATION = 'chargingStationConfiguration',
+}
+
+export class ChargingStationCache {
+  private static instance: ChargingStationCache | null = null;
+  private readonly lruCache: LRUCache<string, any>;
+
+  private constructor() {
+    this.lruCache = new LRUCache<string, any>(1000);
+  }
+
+  public static getInstance(): ChargingStationCache {
+    if (!ChargingStationCache.instance) {
+      ChargingStationCache.instance = new ChargingStationCache();
+    }
+    return ChargingStationCache.instance;
+  }
+
+  public hasChargingStationConfiguration(chargingStationConfigurationHash: string): boolean {
+    return this.has(CacheType.CHARGING_STATION_CONFIGURATION + chargingStationConfigurationHash);
+  }
+
+  public setChargingStationConfiguration(
+    chargingStationConfiguration: ChargingStationConfiguration
+  ): void {
+    if (
+      ChargingStationUtils.isChargingStationConfigurationCacheable(chargingStationConfiguration)
+    ) {
+      this.set(
+        CacheType.CHARGING_STATION_CONFIGURATION + chargingStationConfiguration.configurationHash,
+        chargingStationConfiguration
+      );
+    }
+  }
+
+  public getChargingStationConfiguration(
+    chargingStationConfigurationHash: string
+  ): ChargingStationConfiguration {
+    return this.get(
+      CacheType.CHARGING_STATION_CONFIGURATION + chargingStationConfigurationHash
+    ) as ChargingStationConfiguration;
+  }
+
+  public deleteChargingStationConfiguration(chargingStationConfigurationHash: string): void {
+    this.delete(CacheType.CHARGING_STATION_CONFIGURATION + chargingStationConfigurationHash);
+  }
+
+  public hasChargingStationTemplate(chargingStationTemplateHash: string): boolean {
+    return this.has(CacheType.CHARGING_STATION_TEMPLATE + chargingStationTemplateHash);
+  }
+
+  public setChargingStationTemplate(chargingStationTemplate: ChargingStationTemplate): void {
+    this.set(
+      CacheType.CHARGING_STATION_TEMPLATE + chargingStationTemplate.templateHash,
+      chargingStationTemplate
+    );
+  }
+
+  public getChargingStationTemplate(chargingStationTemplateHash: string): ChargingStationTemplate {
+    return this.get(
+      CacheType.CHARGING_STATION_TEMPLATE + chargingStationTemplateHash
+    ) as ChargingStationTemplate;
+  }
+
+  public deleteChargingStationTemplate(chargingStationTemplateHash: string): void {
+    this.delete(CacheType.CHARGING_STATION_TEMPLATE + chargingStationTemplateHash);
+  }
+
+  public clear(): void {
+    this.lruCache.clear();
+  }
+
+  private has(key: string): boolean {
+    return this.lruCache.has(key);
+  }
+
+  private get(key: string): any {
+    return this.lruCache.get(key);
+  }
+
+  private set(key: string, value: any): void {
+    this.lruCache.set(key, value);
+  }
+
+  private delete(key: string): void {
+    this.lruCache.delete(key);
+  }
+}
index c63a7f27e67411558c7f6f42b3be66859e2fecfa..352de1101d56ca9e569c610ef55fe08a5124b948 100644 (file)
@@ -10,6 +10,7 @@ import { MeterValueMeasurand, MeterValuePhase } from '../types/ocpp/MeterValues'
 import BaseError from '../exception/BaseError';
 import { BootNotificationRequest } from '../types/ocpp/Requests';
 import ChargingStation from './ChargingStation';
+import ChargingStationConfiguration from '../types/ChargingStationConfiguration';
 import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils';
 import ChargingStationInfo from '../types/ChargingStationInfo';
 import Configuration from '../utils/Configuration';
@@ -235,20 +236,11 @@ export class ChargingStationUtils {
   }
 
   public static createStationInfoHash(stationInfo: ChargingStationInfo): void {
-    const previousInfoHash = stationInfo?.infoHash ?? '';
     delete stationInfo.infoHash;
-    const currentInfoHash = crypto
+    stationInfo.infoHash = crypto
       .createHash(Constants.DEFAULT_HASH_ALGORITHM)
       .update(JSON.stringify(stationInfo))
       .digest('hex');
-    if (
-      Utils.isEmptyString(previousInfoHash) ||
-      (!Utils.isEmptyString(previousInfoHash) && currentInfoHash !== previousInfoHash)
-    ) {
-      stationInfo.infoHash = currentInfoHash;
-    } else {
-      stationInfo.infoHash = previousInfoHash;
-    }
   }
 
   public static createSerialNumber(
@@ -561,6 +553,19 @@ export class ChargingStationUtils {
     );
   }
 
+  public static isChargingStationConfigurationCacheable(
+    chargingStationConfiguration: ChargingStationConfiguration
+  ): boolean {
+    return (
+      !Utils.isNullOrUndefined(chargingStationConfiguration?.configurationKey) &&
+      !Utils.isNullOrUndefined(chargingStationConfiguration?.stationInfo) &&
+      !Utils.isNullOrUndefined(chargingStationConfiguration?.configurationHash) &&
+      !Utils.isEmptyArray(chargingStationConfiguration?.configurationKey) &&
+      !Utils.isEmptyObject(chargingStationConfiguration?.stationInfo) &&
+      !Utils.isEmptyString(chargingStationConfiguration?.configurationHash)
+    );
+  }
+
   private static getRandomSerialNumberSuffix(params?: {
     randomBytesLength?: number;
     upperCase?: boolean;
index ab4b45df2904292bed3a58f7c3a5695121c35f60..59fa1b8da2d6b35c8816bfed7f051783ae3bdc9d 100644 (file)
@@ -1,11 +1,13 @@
 import { ChargingStationInfoConfiguration } from './ChargingStationInfo';
 import ChargingStationOcppConfiguration from './ChargingStationOcppConfiguration';
 
-export enum Section {
-  ocppConfiguration,
-  stationInfo,
-}
+// export enum Section {
+//   configurationKey,
+//   stationInfo,
+// }
 
 export default interface ChargingStationConfiguration
   extends ChargingStationInfoConfiguration,
-    ChargingStationOcppConfiguration {}
+    ChargingStationOcppConfiguration {
+  configurationHash?: string;
+}
index db8ff3826a2f8cc5d599ed5c78fc3207414dd3c4..639cf8f7b8f1a54334bbce162bd6953f016ed241 100644 (file)
@@ -68,7 +68,7 @@ export default interface ChargingStationTemplate {
   useConnectorId0?: boolean;
   randomConnectors?: boolean;
   resetTime?: number;
-  autoRegister: boolean;
+  autoRegister?: boolean;
   autoReconnectMaxRetries?: number;
   reconnectExponentialDelay?: boolean;
   registrationMaxRetries?: number;
index efa0826fa9abc1b011daa72256eebcdd3799f23a..d3128469a0f3f8b1d372d202325a1d54fcfb4a47 100644 (file)
@@ -90,6 +90,11 @@ export default class Constants {
   static readonly CHARGING_STATION_DEFAULT_RESET_TIME = 60000; // Ms
   static readonly CHARGING_STATION_ATG_INITIALIZATION_TIME = 1000; // Ms
   static readonly CHARGING_STATION_ATG_DEFAULT_STOP_AFTER_HOURS = 0.25; // Hours
+  static readonly CHARGING_STATION_CONFIGURATION_SECTIONS = Object.freeze([
+    'stationInfo',
+    'configurationKey',
+    'configurationHash',
+  ]);
 
   static readonly DEFAULT_HASH_ALGORITHM = 'sha384';
 
index 2411c605bfc27c44ebd2d70b6bc3643f12a635e3..c7fd875f8f7f09130164ee3126eaebd192280e00 100644 (file)
@@ -10,6 +10,10 @@ export default class Utils {
     return uuid();
   }
 
+  public static equals(obj1: unknown, obj2: unknown): boolean {
+    return JSON.stringify(obj1) === JSON.stringify(obj2);
+  }
+
   public static async sleep(milliSeconds: number): Promise<NodeJS.Timeout> {
     return new Promise((resolve) => setTimeout(resolve as () => void, milliSeconds));
   }