Merge branch 'master' of https://github.wdf.sap.corp/E-Mobility/ev-simulator
authorCalin Crecea <calin.crecea@sap.com>
Wed, 19 May 2021 16:10:45 +0000 (18:10 +0200)
committerCalin Crecea <calin.crecea@sap.com>
Wed, 19 May 2021 16:10:45 +0000 (18:10 +0200)
34 files changed:
.gitmodules
README.md
package-lock.json
package.json
src/assets/station-templates/abb-atg.station-template.json
src/assets/station-templates/abb.station-template.json
src/assets/station-templates/virtual-simple-atg.station-template.json
src/assets/station-templates/virtual-simple.station-template.json
src/assets/station-templates/virtual.station-template.json
src/charging-station/AutomaticTransactionGenerator.ts
src/charging-station/Bootstrap.ts
src/charging-station/ChargingStation.ts
src/charging-station/StationWorker.ts
src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16RequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/OCPPRequestService.ts
src/types/ChargingStationTemplate.ts
src/types/CommandStatistics.ts
src/types/ConfigurationData.ts
src/types/Worker.ts
src/types/ocpp/1.6/Requests.ts
src/types/ocpp/Requests.ts
src/utils/CircularArray.ts
src/utils/Configuration.ts
src/utils/Constants.ts
src/utils/PerformanceStatistics.ts [moved from src/utils/Statistics.ts with 82% similarity]
src/utils/Utils.ts
src/worker/WorkerAbstract.ts
src/worker/WorkerDynamicPool.ts
src/worker/WorkerFactory.ts
src/worker/WorkerSet.ts
src/worker/WorkerStaticPool.ts
tsconfig.json

index 3c1f1aff7e3693fa7e9f00ef68ba2a8ddc58dd68..ac1a6d1297cb8ed14d4e60db4a0449168389457a 100644 (file)
@@ -5,4 +5,4 @@
 [submodule "src/assets/configs-scp"]
        path = src/assets/configs-scp
        url = ../../E-Mobility/ev-scp-config.git
-       branch = master-qa
+  branch = master-qa
index 578ae381c7b1e17c10c2f620f7558cadb2f52f1f..e377862aadb842a8e7261d163c1768fab1fc9eb6 100644 (file)
--- a/README.md
+++ b/README.md
 
 ## Summary
 
-Simple node program to simulate a set of charging stations based on the OCPP-J 1.6 protocol.
+Simple [node.js](https://nodejs.org/) program to simulate a set of charging stations based on the OCPP-J 1.6 protocol.
+
+## Start
 
 To start the program, run: `npm start`.
 
-All the configuration parameters of the program must be within the src/assets/config.json file. A configuration template file is available at [src/assets/config-template.json](src/assets/config-template.json).
+## Configuration syntax
+
+All configuration files are in the JSON standard format.  
+
+The program's global configuration parameters must be within the src/assets/config.json file. A configuration template file is available at [src/assets/config-template.json](src/assets/config-template.json).
+
+All charging station templates are in the directory [src/assets/station-templates](src/assets/station-templates).
+
+A list of RFID tags must be defined for the automatic transaction generator with the default location and name src/assets/authorization-tags.json. A template file is available at [src/assets/authorization-tags-template.json](src/assets/authorization-tags-template.json).
+
+### Global configuration 
+
+**src/assets/config.json**:
+
+Key | Value(s) | Default Value | Value type | Description 
+--- | -------| --------------| ---------- | ------------
+supervisionURLs | | [] | string[] |  array of connection URIs to OCPP-J servers
+distributeStationsToTenantsEqually | true/false | true | boolean | distribute charging stations uniformly to the OCPP-J servers
+statisticsDisplayInterval | | 60 | integer | seconds between charging stations statistics output in the logs 
+workerProcess | workerSet/staticPool/dynamicPool | workerSet | string | worker threads process type
+workerStartDelay | | 500 | integer | milliseconds to wait at charging station worker threads startup
+workerPoolMinSize | | 4 | integer | worker threads pool minimum number of threads
+workerPoolMaxSize | | 16 | integer | worker threads pool maximum number of threads
+workerPoolStrategy | ROUND_ROBIN/LESS_RECENTLY_USED/... | [poolifier](https://github.com/pioardi/poolifier) default: ROUND_ROBBIN | string | worker threads pool [poolifier](https://github.com/pioardi/poolifier) worker choice strategy
+chargingStationsPerWorker | | 1 | integer | number of charging stations per worker threads for the `workerSet` process type
+logConsole | true/false | false | boolean | output logs on the console 
+logFormat | | simple | string | winston log format
+logRotate | true/false | true | boolean | enable daily log files rotation
+logMaxFiles | | 7 | integer | maximum number of log files to keep
+logLevel | emerg/alert/crit/error/warning/notice/info/debug | info | string | winston logging level
+logFile | | combined.log | string | log file relative path
+logErrorFile | | error.log | string | error log file relative path 
+stationTemplateURLs | | {}[] | { file: string; numberOfStations: number; }[] | array of charging template file URIs
+### Charging station template
+
+Key | Value(s) | Default Value | Value type | Description 
+--- | -------| --------------| ---------- | ------------
+supervisionURL | | '' | string | connection URI to OCPP-J server
+ocppVersion | 1.6 | 1.6 | string | OCPP version 
+ocppProtocol | json | json | string | OCPP protocol
+authorizationFile | | '' | string | RFID tags list file relative to src/assets path
+baseName | | '' | string | base name to build charging stations name
+nameSuffix | | '' | string | name suffix to build charging stations name
+fixedName | true/false | false | boolean | use the baseName as the charging stations unique name
+chargePointModel | | '' | string | charging stations model
+chargePointVendor | | '' | string | charging stations vendor
+chargeBoxSerialNumberPrefix | | '' | string | charging stations serial number prefix
+firmwareVersion | | '' | string | charging stations firmware version
+power | | | integer\|integer[] | charging stations maximum power value(s)
+powerSharedByConnectors | true/false | false | boolean | charging stations power shared by its connectors
+powerUnit | W/kW | W | string | charging stations power unit
+currentOutType | AC/DC | AC | string | charging stations current out type
+numberOfPhases | 0/1/3 | AC:3/DC:0 | integer | charging stations number of phase(s) 
+numberOfConnectors | | | integer\|integer[] | charging stations number of connector(s)
+useConnectorId0 | true/false | true | boolean | use connector id 0 definition from the template
+randomConnectors | true/false | false | boolean | randomize runtime connector id affectation from the connector id definition in template
+resetTime | | 60 | integer | seconds to wait before the charging stations come back at reset
+connectionTimeout | | 30 | integer | connection timeout to the OCPP-J server
+autoReconnectMaxRetries | | -1 (unlimited) | integer | connection retries to the OCPP-J server
+reconnectExponentialDelay | true/false | false | boolean | connection delay retry to the OCPP-J server
+registrationMaxRetries | | -1 (unlimited) | integer | charging stations boot notification retries
+enableStatistics | true/false | true | boolean | enable charging stations statistics   
+voltageOut | | AC:230/DC:400 | integer | charging stations voltage out
+Configuration | | | ChargingStationConfiguration | charging stations OCPP configuration parameters
+AutomaticTransactionGenerator | | | AutomaticTransactionGenerator | charging stations ATG configuration
+Connectors | | | Connectors | charging stations connectors configuration
+
+#### Configuration section
+
+```json
+  "Configuration": {
+    "configurationKey": [
+       ...
+       {
+        "key": "StandardKey",
+        "readonly": false,
+        "value": "StandardValue",
+        "visible": true,
+        "reboot": false
+      },
+      ...
+      {
+        "key": "VendorKey",
+        "readonly": false,
+        "value": "VendorValue",
+        "visible": false,
+        "reboot": true
+      },
+      ...
+    ]
+  }
+```
+
+#### AutomaticTransactionGenerator section
+
+```json
+  "AutomaticTransactionGenerator": {
+    "enable": false,
+    "minDuration": 60,
+    "maxDuration": 80,
+    "minDelayBetweenTwoTransactions": 15,
+    "maxDelayBetweenTwoTransactions": 30,
+    "probabilityOfStart": 1,
+    "stopAfterHours": 0.3,
+    "stopOnConnectionFailure": true,
+    "requireAuthorize": false
+  }
+```
+#### Connectors section
+
+```json
+  "Connectors": {
+    "0": {},
+    "1": {
+      "bootStatus": "Available",
+      "MeterValues": [
+        ...
+        {
+          "unit": "A",
+          "measurand": "Current.Import"
+        },
+        ...
+        {
+          "unit": "Wh"
+        },
+        ...
+      ]
+    }
+  },
+```
+
+## OCPP commands
+
+### Version 1.6
 
-All charging station templates are in [src/assets/station-templates](src/assets/station-templates).
+TODO
 
 ## License
 
index 54835f9eaeb4cf18ecf30fa7680d6e3d2dabf0cb..075b4fb413beea2233f72ef7afe10d63de25fca5 100644 (file)
         "kuler": "^2.0.0"
       }
     },
+    "@es-joy/jsdoccomment": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.6.0.tgz",
+      "integrity": "sha512-zT1EtysKMITJ7vE4RvOJqitxk/Str6It8hq+fykxkwLuTyzgak+TnVuVSIyovT/qrEz3i46ypCSXgNtIDYwNOg==",
+      "dev": true,
+      "requires": {
+        "comment-parser": "^1.1.5",
+        "esquery": "^1.4.0",
+        "jsdoctypeparser": "^9.0.0"
+      }
+    },
     "@eslint/eslintrc": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
-      "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz",
+      "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==",
       "dev": true,
       "requires": {
         "ajv": "^6.12.4",
       }
     },
     "@nearform/bubbleprof": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/@nearform/bubbleprof/-/bubbleprof-6.0.1.tgz",
-      "integrity": "sha512-KggBfwy0tS8Z2yRuQPY2zP+4cem0VdGzVbovtUMRznKNznXTpqEdYjicmkU9XX3bT+6x4Mk2Q7VH5gPlyN84cQ==",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@nearform/bubbleprof/-/bubbleprof-7.0.0.tgz",
+      "integrity": "sha512-fKXaqklgkt4UuRaV/8nc4e3bBjWhA+cPGhQareLl9dDZd/DRnMXkyMbzElZl2QFnvcQoe1rRdtaLMm8ssphxFg==",
       "dev": true,
       "requires": {
-        "@nearform/clinic-common": "^5.0.0",
+        "@nearform/clinic-common": "^6.0.0",
         "@nearform/node-trace-log-join": "2.0.0-0",
         "@nearform/trace-events-parser": "^1.0.4",
         "array-flatten": "^3.0.0",
       }
     },
     "@nearform/clinic-common": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/@nearform/clinic-common/-/clinic-common-5.0.0.tgz",
-      "integrity": "sha512-W0OojaQb9xc6sEUJOg8PpgX9S5B42soJYJZUMH11p4kQfu3/4Ygp6eVPc5Ye/J+mmzVQD/553ZQgavJMwkBrbg==",
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@nearform/clinic-common/-/clinic-common-6.0.0.tgz",
+      "integrity": "sha512-bt0RKC1MDmS+l6vANEl0KE/l1OgN+FtT6wzOYPYTNjZYg9cR4gLyQeE0/KrCccChXuL2Nh+9RdMtfjJEI5KxNA==",
       "dev": true,
       "requires": {
         "brfs": "^2.0.1",
           }
         },
         "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
-          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
+          "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
       }
     },
     "@nearform/doctor": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/@nearform/doctor/-/doctor-7.0.1.tgz",
-      "integrity": "sha512-SP/ABddWzGPfGLm6gOUsI9C1XZwogyA6TfTfy1/3CqJcmjg+RSZBWxbtyc+FmQdDOXVNElNn/yNaMSiVINXwaA==",
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/@nearform/doctor/-/doctor-8.0.0.tgz",
+      "integrity": "sha512-XB3o3p0arxsYLAER9NwOc89YBv4ir4rQE3QIHfFZOtySHNEAjOxxfZI7Pev9ZBDmTetvSgHLm55bjTK2DT5+TA==",
       "dev": true,
       "requires": {
-        "@nearform/clinic-common": "^5.0.0",
+        "@nearform/clinic-common": "^6.0.0",
         "@nearform/node-trace-log-join": "2.0.0-0",
         "@nearform/trace-events-parser": "^1.0.4",
         "@tensorflow/tfjs-core": "^1.2.1",
             "ms": "2.1.2"
           }
         },
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+          "dev": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
         "ms": {
           "version": "2.1.2",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
           "dev": true
         },
         "semver": {
-          "version": "7.3.2",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
-          "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+          "version": "7.3.5",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
           "dev": true
         }
       }
     },
     "@nearform/flame": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/@nearform/flame/-/flame-8.0.1.tgz",
-      "integrity": "sha512-BzjjJgOQuI/DHo7n8b3H8EZDU9Ul7nMdGs/qg0JrKNVHvIf5Rvo5D3TQJtQwVYEAik27R1o39X5CVQyhxtOqTA==",
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/@nearform/flame/-/flame-9.0.0.tgz",
+      "integrity": "sha512-KBH/kbbZvCOali8M5neULbFLCN1WHjFbaRWVVzFDqWPkehkrY3kU0K2K/3NfzKJH+yiflbT+D8g9KxffPNM0Cg==",
       "dev": true,
       "requires": {
         "0x": "^4.10.2",
-        "@nearform/clinic-common": "^5.0.0",
+        "@nearform/clinic-common": "^6.0.0",
         "copy-to-clipboard": "^3.0.8",
         "d3-array": "^2.0.2",
         "d3-fg": "^6.13.1",
         "rimraf": "^3.0.2"
       }
     },
+    "@nearform/heap-profiler": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@nearform/heap-profiler/-/heap-profiler-2.0.0.tgz",
+      "integrity": "sha512-846CWyq3Ky5rzcl8Z3S+VT3z6GQSlYD1G/dqbtANu29NUHoCO+W7tOZRK6eA6FjLHnNX0DvP1Mrt2oFBPnkxLw==",
+      "dev": true,
+      "requires": {
+        "abort-controller": "^3.0.0",
+        "sonic-boom": "^1.0.1"
+      }
+    },
     "@nearform/multistream": {
       "version": "5.0.0-2",
       "resolved": "https://registry.npmjs.org/@nearform/multistream/-/multistream-5.0.0-2.tgz",
         "seedrandom": "2.4.3"
       }
     },
-    "@types/estree": {
-      "version": "0.0.46",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz",
-      "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==",
-      "dev": true
-    },
     "@types/fs-extra": {
       "version": "8.1.1",
       "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.1.tgz",
       "dev": true
     },
     "@types/node": {
-      "version": "14.14.37",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz",
-      "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==",
+      "version": "14.14.45",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.45.tgz",
+      "integrity": "sha512-DssMqTV9UnnoxDWu959sDLZzfvqCF0qDNRjaWeYSui9xkFe61kKo4l1TWNTQONpuXEm+gLMRvdlzvNHBamzmEw==",
       "dev": true
     },
     "@types/offscreencanvas": {
       "dev": true
     },
     "@types/ws": {
-      "version": "7.4.1",
-      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.1.tgz",
-      "integrity": "sha512-ISCK1iFnR+jYv7+jLNX0wDqesZ/5RAeY3wUx6QaphmocphU61h+b+PHjS18TF4WIPTu/MMzxIq2PHr32o2TS5Q==",
+      "version": "7.4.4",
+      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.4.tgz",
+      "integrity": "sha512-d/7W23JAXPodQNbOZNXvl2K+bqAQrCMwlh/nuQsPSQk6Fq0opHoPrUw43aHsvSbIiQPr8Of2hkFbnz1XBFVyZQ==",
       "dev": true,
       "requires": {
         "@types/node": "*"
       }
     },
     "@typescript-eslint/eslint-plugin": {
-      "version": "4.22.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.0.tgz",
-      "integrity": "sha512-U8SP9VOs275iDXaL08Ln1Fa/wLXfj5aTr/1c0t0j6CdbOnxh+TruXu1p4I0NAvdPBQgoPjHsgKn28mOi0FzfoA==",
+      "version": "4.24.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.24.0.tgz",
+      "integrity": "sha512-qbCgkPM7DWTsYQGjx9RTuQGswi+bEt0isqDBeo+CKV0953zqI0Tp7CZ7Fi9ipgFA6mcQqF4NOVNwS/f2r6xShw==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/experimental-utils": "4.22.0",
-        "@typescript-eslint/scope-manager": "4.22.0",
+        "@typescript-eslint/experimental-utils": "4.24.0",
+        "@typescript-eslint/scope-manager": "4.24.0",
         "debug": "^4.1.1",
         "functional-red-black-tree": "^1.0.1",
         "lodash": "^4.17.15",
       }
     },
     "@typescript-eslint/experimental-utils": {
-      "version": "4.22.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz",
-      "integrity": "sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg==",
+      "version": "4.24.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.24.0.tgz",
+      "integrity": "sha512-IwTT2VNDKH1h8RZseMH4CcYBz6lTvRoOLDuuqNZZoThvfHEhOiZPQCow+5El3PtyxJ1iDr6UXZwYtE3yZQjhcw==",
       "dev": true,
       "requires": {
         "@types/json-schema": "^7.0.3",
-        "@typescript-eslint/scope-manager": "4.22.0",
-        "@typescript-eslint/types": "4.22.0",
-        "@typescript-eslint/typescript-estree": "4.22.0",
+        "@typescript-eslint/scope-manager": "4.24.0",
+        "@typescript-eslint/types": "4.24.0",
+        "@typescript-eslint/typescript-estree": "4.24.0",
         "eslint-scope": "^5.0.0",
         "eslint-utils": "^2.0.0"
       }
     },
     "@typescript-eslint/parser": {
-      "version": "4.22.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.22.0.tgz",
-      "integrity": "sha512-z/bGdBJJZJN76nvAY9DkJANYgK3nlRstRRi74WHm3jjgf2I8AglrSY+6l7ogxOmn55YJ6oKZCLLy+6PW70z15Q==",
+      "version": "4.24.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.24.0.tgz",
+      "integrity": "sha512-dj1ZIh/4QKeECLb2f/QjRwMmDArcwc2WorWPRlB8UNTZlY1KpTVsbX7e3ZZdphfRw29aTFUSNuGB8w9X5sS97w==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/scope-manager": "4.22.0",
-        "@typescript-eslint/types": "4.22.0",
-        "@typescript-eslint/typescript-estree": "4.22.0",
+        "@typescript-eslint/scope-manager": "4.24.0",
+        "@typescript-eslint/types": "4.24.0",
+        "@typescript-eslint/typescript-estree": "4.24.0",
         "debug": "^4.1.1"
       }
     },
     "@typescript-eslint/scope-manager": {
-      "version": "4.22.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz",
-      "integrity": "sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q==",
+      "version": "4.24.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.24.0.tgz",
+      "integrity": "sha512-9+WYJGDnuC9VtYLqBhcSuM7du75fyCS/ypC8c5g7Sdw7pGL4NDTbeH38eJPfzIydCHZDoOgjloxSAA3+4l/zsA==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.22.0",
-        "@typescript-eslint/visitor-keys": "4.22.0"
+        "@typescript-eslint/types": "4.24.0",
+        "@typescript-eslint/visitor-keys": "4.24.0"
       }
     },
     "@typescript-eslint/types": {
-      "version": "4.22.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.0.tgz",
-      "integrity": "sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA==",
+      "version": "4.24.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.24.0.tgz",
+      "integrity": "sha512-tkZUBgDQKdvfs8L47LaqxojKDE+mIUmOzdz7r+u+U54l3GDkTpEbQ1Jp3cNqqAU9vMUCBA1fitsIhm7yN0vx9Q==",
       "dev": true
     },
     "@typescript-eslint/typescript-estree": {
-      "version": "4.22.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz",
-      "integrity": "sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg==",
+      "version": "4.24.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.24.0.tgz",
+      "integrity": "sha512-kBDitL/by/HK7g8CYLT7aKpAwlR8doshfWz8d71j97n5kUa5caHWvY0RvEUEanL/EqBJoANev8Xc/mQ6LLwXGA==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.22.0",
-        "@typescript-eslint/visitor-keys": "4.22.0",
+        "@typescript-eslint/types": "4.24.0",
+        "@typescript-eslint/visitor-keys": "4.24.0",
         "debug": "^4.1.1",
         "globby": "^11.0.1",
         "is-glob": "^4.0.1",
       }
     },
     "@typescript-eslint/visitor-keys": {
-      "version": "4.22.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz",
-      "integrity": "sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw==",
+      "version": "4.24.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.24.0.tgz",
+      "integrity": "sha512-4ox1sjmGHIxjEDBnMCtWFFhErXtKA1Ec0sBpuz0fqf3P+g3JFGyTxxbF06byw0FRsPnnbq44cKivH7Ks1/0s6g==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.22.0",
+        "@typescript-eslint/types": "4.24.0",
         "eslint-visitor-keys": "^2.0.0"
       }
     },
         "through": ">=2.2.7 <3"
       }
     },
+    "abort-controller": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+      "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+      "dev": true,
+      "requires": {
+        "event-target-shim": "^5.0.0"
+      }
+    },
     "acorn": {
       "version": "7.4.1",
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
             "get-intrinsic": "^1.0.2"
           }
         },
-        "es-abstract": {
-          "version": "1.18.0",
-          "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz",
-          "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "es-to-primitive": "^1.2.1",
-            "function-bind": "^1.1.1",
-            "get-intrinsic": "^1.1.1",
-            "has": "^1.0.3",
-            "has-symbols": "^1.0.2",
-            "is-callable": "^1.2.3",
-            "is-negative-zero": "^2.0.1",
-            "is-regex": "^1.1.2",
-            "is-string": "^1.0.5",
-            "object-inspect": "^1.9.0",
-            "object-keys": "^1.1.1",
-            "object.assign": "^4.1.2",
-            "string.prototype.trimend": "^1.0.4",
-            "string.prototype.trimstart": "^1.0.4",
-            "unbox-primitive": "^1.0.0"
-          },
-          "dependencies": {
-            "has-symbols": {
-              "version": "1.0.2",
-              "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
-              "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
-              "dev": true
-            }
-          }
-        },
         "get-intrinsic": {
           "version": "1.1.1",
           "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
             "has": "^1.0.3",
             "has-symbols": "^1.0.1"
           }
-        },
-        "is-callable": {
-          "version": "1.2.3",
-          "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz",
-          "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==",
-          "dev": true
-        },
-        "is-regex": {
-          "version": "1.1.2",
-          "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz",
-          "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "has-symbols": "^1.0.1"
-          }
-        },
-        "object-inspect": {
-          "version": "1.9.0",
-          "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz",
-          "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==",
-          "dev": true
-        },
-        "string.prototype.trimend": {
-          "version": "1.0.4",
-          "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
-          "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "define-properties": "^1.1.3"
-          }
-        },
-        "string.prototype.trimstart": {
-          "version": "1.0.4",
-          "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
-          "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "define-properties": "^1.1.3"
-          }
         }
       }
     },
         "call-bind": "^1.0.0",
         "define-properties": "^1.1.3",
         "es-abstract": "^1.18.0-next.1"
-      },
-      "dependencies": {
-        "es-abstract": {
-          "version": "1.18.0",
-          "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz",
-          "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "es-to-primitive": "^1.2.1",
-            "function-bind": "^1.1.1",
-            "get-intrinsic": "^1.1.1",
-            "has": "^1.0.3",
-            "has-symbols": "^1.0.2",
-            "is-callable": "^1.2.3",
-            "is-negative-zero": "^2.0.1",
-            "is-regex": "^1.1.2",
-            "is-string": "^1.0.5",
-            "object-inspect": "^1.9.0",
-            "object-keys": "^1.1.1",
-            "object.assign": "^4.1.2",
-            "string.prototype.trimend": "^1.0.4",
-            "string.prototype.trimstart": "^1.0.4",
-            "unbox-primitive": "^1.0.0"
-          },
-          "dependencies": {
-            "call-bind": {
-              "version": "1.0.2",
-              "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
-              "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
-              "dev": true,
-              "requires": {
-                "function-bind": "^1.1.1",
-                "get-intrinsic": "^1.0.2"
-              }
-            }
-          }
-        },
-        "get-intrinsic": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
-          "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
-          "dev": true,
-          "requires": {
-            "function-bind": "^1.1.1",
-            "has": "^1.0.3",
-            "has-symbols": "^1.0.1"
-          }
-        },
-        "has-symbols": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
-          "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
-          "dev": true
-        },
-        "is-callable": {
-          "version": "1.2.3",
-          "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz",
-          "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==",
-          "dev": true
-        },
-        "is-regex": {
-          "version": "1.1.2",
-          "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz",
-          "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "has-symbols": "^1.0.1"
-          },
-          "dependencies": {
-            "call-bind": {
-              "version": "1.0.2",
-              "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
-              "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
-              "dev": true,
-              "requires": {
-                "function-bind": "^1.1.1",
-                "get-intrinsic": "^1.0.2"
-              }
-            }
-          }
-        },
-        "object-inspect": {
-          "version": "1.9.0",
-          "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz",
-          "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==",
-          "dev": true
-        },
-        "string.prototype.trimend": {
-          "version": "1.0.4",
-          "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
-          "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "define-properties": "^1.1.3"
-          },
-          "dependencies": {
-            "call-bind": {
-              "version": "1.0.2",
-              "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
-              "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
-              "dev": true,
-              "requires": {
-                "function-bind": "^1.1.1",
-                "get-intrinsic": "^1.0.2"
-              }
-            }
-          }
-        },
-        "string.prototype.trimstart": {
-          "version": "1.0.4",
-          "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
-          "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "define-properties": "^1.1.3"
-          },
-          "dependencies": {
-            "call-bind": {
-              "version": "1.0.2",
-              "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
-              "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
-              "dev": true,
-              "requires": {
-                "function-bind": "^1.1.1",
-                "get-intrinsic": "^1.0.2"
-              }
-            }
-          }
-        }
       }
     },
     "arrify": {
       },
       "dependencies": {
         "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
           "dev": true
         }
       }
       "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
       "dev": true
     },
+    "at-least-node": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+      "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+      "dev": true
+    },
+    "atomic-sleep": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
+      "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
+      "dev": true
+    },
     "autocannon": {
       "version": "6.5.0",
       "resolved": "https://registry.npmjs.org/autocannon/-/autocannon-6.5.0.tgz",
           }
         },
         "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
-          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
+          "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
       "dev": true
     },
     "bn.js": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz",
-      "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==",
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
+      "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==",
       "dev": true
     },
     "boxen": {
       },
       "dependencies": {
         "resolve": {
-          "version": "1.19.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
-          "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
+          "version": "1.20.0",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
+          "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
           "dev": true,
           "requires": {
-            "is-core-module": "^2.1.0",
+            "is-core-module": "^2.2.0",
             "path-parse": "^1.0.6"
           }
         }
       }
     },
     "cli-spinners": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.5.0.tgz",
-      "integrity": "sha512-PC+AmIuK04E6aeSs/pUccSujsTzBhu4HzC2dL+CfJB/Jcc2qTRbEwZQDfIUpt2Xl8BodYBEq8w4fc0kU2I9DjQ==",
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz",
+      "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==",
       "dev": true
     },
     "cli-table3": {
           "dev": true
         },
         "string-width": {
-          "version": "4.2.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
-          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+          "version": "4.2.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+          "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
           "dev": true,
           "requires": {
             "emoji-regex": "^8.0.0",
       "dev": true
     },
     "clinic": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/clinic/-/clinic-8.0.1.tgz",
-      "integrity": "sha512-SJ/VBzvJefNJ4I3HBpK2nQi3znf/E4IOPKIaOENjlX9KeuQqUei5uoUELgay5y1XBfy8rc0bk9M+0eK5LtaQnw==",
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/clinic/-/clinic-9.0.0.tgz",
+      "integrity": "sha512-w6fchhCY6LrdNsJ/Kdymuv2gaB0jdX1Ql2t0MCAC4lr/ulY4+sPAB+nATl40OrGXKhPRlJINb4QebsnIvLv+3A==",
       "dev": true,
       "requires": {
-        "@nearform/bubbleprof": "^6.0.1",
-        "@nearform/doctor": "^7.0.1",
-        "@nearform/flame": "^8.0.1",
+        "@nearform/bubbleprof": "^7.0.0",
+        "@nearform/doctor": "^8.0.0",
+        "@nearform/flame": "^9.0.0",
         "any-shell-escape": "^0.1.1",
         "async": "^3.0.1",
         "autocannon": "^6.5.0",
         "execspawn": "^1.0.1",
         "insight": "^0.10.1",
         "minimist": "^1.2.0",
+        "node-clinic-heap-profiler": "^1.0.0",
         "open": "^7.3.0",
         "ora": "^5.1.0",
         "rimraf": "^3.0.0",
           }
         },
         "boxen": {
-          "version": "4.2.0",
-          "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
-          "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==",
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.0.1.tgz",
+          "integrity": "sha512-49VBlw+PrWEF51aCmy7QIteYPIFZxSpvqBdP/2itCPPlJ49kj9zg/XPRFrdkne2W+CfwXUls8exMvu1RysZpKA==",
           "dev": true,
           "requires": {
             "ansi-align": "^3.0.0",
-            "camelcase": "^5.3.1",
-            "chalk": "^3.0.0",
-            "cli-boxes": "^2.2.0",
-            "string-width": "^4.1.0",
-            "term-size": "^2.1.0",
-            "type-fest": "^0.8.1",
-            "widest-line": "^3.1.0"
-          },
-          "dependencies": {
-            "chalk": {
-              "version": "3.0.0",
-              "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-              "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-              "dev": true,
-              "requires": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-              }
-            }
+            "camelcase": "^6.2.0",
+            "chalk": "^4.1.0",
+            "cli-boxes": "^2.2.1",
+            "string-width": "^4.2.0",
+            "type-fest": "^0.20.2",
+            "widest-line": "^3.1.0",
+            "wrap-ansi": "^7.0.0"
           }
         },
+        "camelcase": {
+          "version": "6.2.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
+          "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
+          "dev": true
+        },
         "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
-          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
+          "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
           }
         },
         "global-dirs": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz",
-          "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==",
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz",
+          "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==",
           "dev": true,
           "requires": {
-            "ini": "^1.3.5"
+            "ini": "2.0.0"
           }
         },
         "got": {
           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
           "dev": true
         },
+        "ini": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+          "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+          "dev": true
+        },
         "is-ci": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
           }
         },
         "is-installed-globally": {
-          "version": "0.3.2",
-          "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz",
-          "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==",
+          "version": "0.4.0",
+          "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
+          "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
           "dev": true,
           "requires": {
-            "global-dirs": "^2.0.1",
-            "is-path-inside": "^3.0.1"
+            "global-dirs": "^3.0.0",
+            "is-path-inside": "^3.0.2"
           }
         },
         "is-npm": {
           "dev": true
         },
         "is-path-inside": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz",
-          "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==",
+          "version": "3.0.3",
+          "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+          "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
           "dev": true
         },
         "latest-version": {
             "package-json": "^6.3.0"
           }
         },
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+          "dev": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
         "make-dir": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
           }
         },
         "semver": {
-          "version": "7.3.2",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
-          "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
-          "dev": true
+          "version": "7.3.5",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
         },
         "semver-diff": {
           "version": "3.1.1",
           }
         },
         "string-width": {
-          "version": "4.2.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
-          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+          "version": "4.2.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+          "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
           "dev": true,
           "requires": {
             "emoji-regex": "^8.0.0",
             "has-flag": "^4.0.0"
           }
         },
-        "term-size": {
-          "version": "2.2.1",
-          "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
-          "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==",
+        "type-fest": {
+          "version": "0.20.2",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+          "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
           "dev": true
         },
         "unique-string": {
           }
         },
         "update-notifier": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.0.1.tgz",
-          "integrity": "sha512-BuVpRdlwxeIOvmc32AGYvO1KVdPlsmqSh8KDDBxS6kDE5VR7R8OMP1d8MdhaVBvxl4H3551k9akXr0Y1iIB2Wg==",
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz",
+          "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==",
           "dev": true,
           "requires": {
-            "boxen": "^4.2.0",
+            "boxen": "^5.0.0",
             "chalk": "^4.1.0",
             "configstore": "^5.0.1",
             "has-yarn": "^2.1.0",
             "import-lazy": "^2.1.0",
             "is-ci": "^2.0.0",
-            "is-installed-globally": "^0.3.2",
+            "is-installed-globally": "^0.4.0",
             "is-npm": "^5.0.0",
             "is-yarn-global": "^0.3.0",
             "latest-version": "^5.1.0",
             "pupa": "^2.1.1",
-            "semver": "^7.3.2",
+            "semver": "^7.3.4",
             "semver-diff": "^3.1.1",
             "xdg-basedir": "^4.0.0"
           }
             "string-width": "^4.0.0"
           }
         },
+        "wrap-ansi": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+          "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "string-width": "^4.1.0",
+            "strip-ansi": "^6.0.0"
+          },
+          "dependencies": {
+            "ansi-regex": {
+              "version": "5.0.0",
+              "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+              "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+              "dev": true
+            },
+            "strip-ansi": {
+              "version": "6.0.0",
+              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+              "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+              "dev": true,
+              "requires": {
+                "ansi-regex": "^5.0.0"
+              }
+            }
+          }
+        },
         "write-file-atomic": {
           "version": "3.0.3",
           "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
           "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
           "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
           "dev": true
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+          "dev": true
         }
       }
     },
       "dev": true
     },
     "comment-parser": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.1.2.tgz",
-      "integrity": "sha512-AOdq0i8ghZudnYv8RUnHrhTgafUGs61Rdz9jemU5x2lnZwAWyOq7vySo626K59e1fVKH1xSRorJwPVRLSWOoAQ==",
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.1.5.tgz",
+      "integrity": "sha512-RePCE4leIhBlmrqiYTvaqEeGYg7qpSl4etaIabKtdOQVi+mSTIBBklGUwIr79GXYnl3LpMwmDw4KeR2stNc6FA==",
       "dev": true
     },
     "commist": {
       "dev": true
     },
     "contains-path": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
-      "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=",
-      "dev": true
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-1.0.0.tgz",
+      "integrity": "sha1-NFizMhhWA+ju0Y9RjUoQiIo6vJE=",
+      "dev": true,
+      "requires": {
+        "normalize-path": "^2.1.1",
+        "path-starts-with": "^1.0.0"
+      }
     },
     "convert-source-map": {
       "version": "1.7.0",
       },
       "dependencies": {
         "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
           "dev": true
         }
       }
       }
     },
     "d3-array": {
-      "version": "2.8.0",
-      "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.8.0.tgz",
-      "integrity": "sha512-6V272gsOeg7+9pTW1jSYOR1QE37g95I3my1hBmY+vOUNHRrk9yt4OTz/gK7PMkVAVDrYYq4mq3grTiZ8iJdNIw==",
-      "dev": true
+      "version": "2.12.1",
+      "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
+      "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
+      "dev": true,
+      "requires": {
+        "internmap": "^1.0.0"
+      }
     },
     "d3-axis": {
       "version": "1.0.12",
       "dev": true
     },
     "d3-scale": {
-      "version": "3.2.3",
-      "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.3.tgz",
-      "integrity": "sha512-8E37oWEmEzj57bHcnjPVOBS3n4jqakOeuv1EDdQSiSrYnMCBdMd3nc4HtKk7uia8DUHcY/CGuJ42xxgtEYrX0g==",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz",
+      "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==",
       "dev": true,
       "requires": {
         "d3-array": "^2.3.0",
         "d3-format": "1 - 2",
         "d3-interpolate": "1.2.0 - 2",
-        "d3-time": "1 - 2",
+        "d3-time": "^2.1.1",
         "d3-time-format": "2 - 3"
+      },
+      "dependencies": {
+        "d3-time": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz",
+          "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==",
+          "dev": true,
+          "requires": {
+            "d3-array": "2"
+          }
+        }
       }
     },
     "d3-selection": {
       "dev": true
     },
     "debounce": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz",
-      "integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
+      "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==",
       "dev": true
     },
     "debug": {
       },
       "dependencies": {
         "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
           "dev": true
         }
       }
       }
     },
     "es-abstract": {
-      "version": "1.17.7",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
-      "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
+      "version": "1.18.0",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz",
+      "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==",
       "dev": true,
       "requires": {
+        "call-bind": "^1.0.2",
         "es-to-primitive": "^1.2.1",
         "function-bind": "^1.1.1",
+        "get-intrinsic": "^1.1.1",
         "has": "^1.0.3",
-        "has-symbols": "^1.0.1",
-        "is-callable": "^1.2.2",
-        "is-regex": "^1.1.1",
-        "object-inspect": "^1.8.0",
+        "has-symbols": "^1.0.2",
+        "is-callable": "^1.2.3",
+        "is-negative-zero": "^2.0.1",
+        "is-regex": "^1.1.2",
+        "is-string": "^1.0.5",
+        "object-inspect": "^1.9.0",
         "object-keys": "^1.1.1",
-        "object.assign": "^4.1.1",
-        "string.prototype.trimend": "^1.0.1",
-        "string.prototype.trimstart": "^1.0.1"
+        "object.assign": "^4.1.2",
+        "string.prototype.trimend": "^1.0.4",
+        "string.prototype.trimstart": "^1.0.4",
+        "unbox-primitive": "^1.0.0"
+      },
+      "dependencies": {
+        "call-bind": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+          "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "get-intrinsic": "^1.0.2"
+          }
+        },
+        "get-intrinsic": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+          "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "has": "^1.0.3",
+            "has-symbols": "^1.0.1"
+          }
+        },
+        "has-symbols": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
+          "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
+          "dev": true
+        },
+        "is-callable": {
+          "version": "1.2.3",
+          "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz",
+          "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==",
+          "dev": true
+        }
       }
     },
     "es-to-primitive": {
       }
     },
     "eslint": {
-      "version": "7.24.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.24.0.tgz",
-      "integrity": "sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==",
+      "version": "7.26.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz",
+      "integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "7.12.11",
-        "@eslint/eslintrc": "^0.4.0",
+        "@eslint/eslintrc": "^0.4.1",
         "ajv": "^6.10.0",
         "chalk": "^4.0.0",
         "cross-spawn": "^7.0.2",
           }
         },
         "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
-          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
+          "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
             "type-check": "~0.4.0"
           }
         },
-        "lodash": {
-          "version": "4.17.21",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
-          "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
-          "dev": true
-        },
         "lru-cache": {
           "version": "6.0.0",
           "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
             "ms": "2.0.0"
           }
         },
-        "is-core-module": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
-          "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
-          "dev": true,
-          "requires": {
-            "has": "^1.0.3"
-          }
-        },
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
       }
     },
     "eslint-module-utils": {
-      "version": "2.6.0",
-      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz",
-      "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==",
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz",
+      "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==",
       "dev": true,
       "requires": {
-        "debug": "^2.6.9",
+        "debug": "^3.2.7",
         "pkg-dir": "^2.0.0"
       },
       "dependencies": {
         "debug": {
-          "version": "2.6.9",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
           "dev": true,
           "requires": {
-            "ms": "2.0.0"
+            "ms": "^2.1.1"
           }
         },
         "find-up": {
             "path-exists": "^3.0.0"
           }
         },
-        "ms": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-          "dev": true
-        },
         "p-limit": {
           "version": "1.3.0",
           "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
       }
     },
     "eslint-plugin-import": {
-      "version": "2.22.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz",
-      "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==",
+      "version": "2.23.2",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.2.tgz",
+      "integrity": "sha512-LmNoRptHBxOP+nb0PIKz1y6OSzCJlB+0g0IGS3XV4KaKk2q4szqQ6s6F1utVf5ZRkxk/QOTjdxe7v4VjS99Bsg==",
       "dev": true,
       "requires": {
-        "array-includes": "^3.1.1",
-        "array.prototype.flat": "^1.2.3",
-        "contains-path": "^0.1.0",
+        "array-includes": "^3.1.3",
+        "array.prototype.flat": "^1.2.4",
+        "contains-path": "^1.0.0",
         "debug": "^2.6.9",
-        "doctrine": "1.5.0",
+        "doctrine": "^2.1.0",
         "eslint-import-resolver-node": "^0.3.4",
-        "eslint-module-utils": "^2.6.0",
+        "eslint-module-utils": "^2.6.1",
+        "find-up": "^2.0.0",
         "has": "^1.0.3",
+        "is-core-module": "^2.4.0",
         "minimatch": "^3.0.4",
-        "object.values": "^1.1.1",
-        "read-pkg-up": "^2.0.0",
-        "resolve": "^1.17.0",
+        "object.values": "^1.1.3",
+        "pkg-up": "^2.0.0",
+        "read-pkg-up": "^3.0.0",
+        "resolve": "^1.20.0",
         "tsconfig-paths": "^3.9.0"
       },
       "dependencies": {
           }
         },
         "doctrine": {
-          "version": "1.5.0",
-          "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
-          "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+          "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
           "dev": true,
           "requires": {
-            "esutils": "^2.0.2",
-            "isarray": "^1.0.0"
+            "esutils": "^2.0.2"
           }
         },
         "find-up": {
             "locate-path": "^2.0.0"
           }
         },
-        "is-core-module": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
-          "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
-          "dev": true,
-          "requires": {
-            "has": "^1.0.3"
-          }
-        },
         "load-json-file": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
-          "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+          "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
           "dev": true,
           "requires": {
             "graceful-fs": "^4.1.2",
-            "parse-json": "^2.2.0",
-            "pify": "^2.0.0",
+            "parse-json": "^4.0.0",
+            "pify": "^3.0.0",
             "strip-bom": "^3.0.0"
           }
         },
           "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
           "dev": true
         },
+        "parse-json": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+          "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+          "dev": true,
+          "requires": {
+            "error-ex": "^1.3.1",
+            "json-parse-better-errors": "^1.0.1"
+          }
+        },
         "path-type": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
-          "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+          "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
           "dev": true,
           "requires": {
-            "pify": "^2.0.0"
+            "pify": "^3.0.0"
           }
         },
+        "pify": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+          "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+          "dev": true
+        },
         "read-pkg": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
-          "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+          "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
           "dev": true,
           "requires": {
-            "load-json-file": "^2.0.0",
+            "load-json-file": "^4.0.0",
             "normalize-package-data": "^2.3.2",
-            "path-type": "^2.0.0"
+            "path-type": "^3.0.0"
           }
         },
         "read-pkg-up": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
-          "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
+          "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=",
           "dev": true,
           "requires": {
             "find-up": "^2.0.0",
-            "read-pkg": "^2.0.0"
+            "read-pkg": "^3.0.0"
           }
         },
         "resolve": {
       }
     },
     "eslint-plugin-jsdoc": {
-      "version": "32.3.0",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-32.3.0.tgz",
-      "integrity": "sha512-zyx7kajDK+tqS1bHuY5sapkad8P8KT0vdd/lE55j47VPG2MeenSYuIY/M/Pvmzq5g0+3JB+P3BJGUXmHxtuKPQ==",
+      "version": "34.7.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-34.7.0.tgz",
+      "integrity": "sha512-H2zrJorJfocd//PNNYsrPxWNAQjHONzIHGZ9CFYISyfZCOTXYUzH8CyA95LHYpZqGf5UEueHiwl+0bzWreqAjQ==",
       "dev": true,
       "requires": {
-        "comment-parser": "1.1.2",
+        "@es-joy/jsdoccomment": "^0.6.0",
+        "comment-parser": "1.1.5",
         "debug": "^4.3.1",
+        "esquery": "^1.4.0",
         "jsdoctypeparser": "^9.0.0",
-        "lodash": "^4.17.20",
+        "lodash": "^4.17.21",
         "regextras": "^0.7.1",
-        "semver": "^7.3.4",
+        "semver": "^7.3.5",
         "spdx-expression-parse": "^3.0.1"
       },
       "dependencies": {
             "ms": "2.1.2"
           }
         },
-        "lodash": {
-          "version": "4.17.21",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
-          "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
-          "dev": true
-        },
         "lru-cache": {
           "version": "6.0.0",
           "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
         "es5-ext": "~0.10.14"
       }
     },
+    "event-target-shim": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+      "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+      "dev": true
+    },
     "events": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
-      "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
       "dev": true
     },
     "evp_bytestokey": {
       },
       "dependencies": {
         "type": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz",
-          "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==",
+          "version": "2.5.0",
+          "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz",
+          "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==",
           "dev": true
         }
       }
         "rimraf": "^3.0.2"
       }
     },
+    "flatstr": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz",
+      "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==",
+      "dev": true
+    },
     "flatted": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz",
       "dev": true
     },
     "form-data": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz",
-      "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
+      "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
       "dev": true,
       "requires": {
         "asynckit": "^0.4.0",
       }
     },
     "hosted-git-info": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
-      "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
+      "version": "2.8.9",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+      "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
       "dev": true
     },
     "hsl-to-rgb-for-reals": {
       "dev": true
     },
     "http-parser-js": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz",
-      "integrity": "sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==",
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz",
+      "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==",
       "dev": true
     },
     "http-signature": {
       "dev": true
     },
     "hyperid": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/hyperid/-/hyperid-2.0.5.tgz",
-      "integrity": "sha512-kg0+DOmWo3HSFvWWMCQJJhzEB4kg5z/83l4eFDaeAMJ5E2zbQzTEewAmVtOqdRElU9yRFJhCOuegUk0M6RZfiw==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/hyperid/-/hyperid-2.1.0.tgz",
+      "integrity": "sha512-cSakhxbUsaIuqjfvvcUuvl/Fl342J65xgLLYrYxSSr9qmJ/EJK+S8crS6mIlQd/a7i+Pe4D0MgSrtZPLze+aCw==",
       "dev": true,
       "requires": {
         "uuid": "^3.4.0",
         }
       }
     },
+    "internmap": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
+      "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==",
+      "dev": true
+    },
     "iota-array": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz",
       "dev": true
     },
     "is-any-array": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/is-any-array/-/is-any-array-0.1.0.tgz",
-      "integrity": "sha512-6Kkl1RnvfdkmXM6ZlP+kELGBMA74Nq5pSOm9gIKDaPRe9KQlIJzonrOgq0Jzn/iElB6F2/olpLgWYeVySzrSRg==",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-any-array/-/is-any-array-1.0.0.tgz",
+      "integrity": "sha512-0o0ZsgObnylv72nO39P6M+PL7jPUEx39O6BEfZuX36IKPy/RpdudxluAIaRn/LZi5eVPDMlMBaLABzOK6bwPlw==",
+      "dev": true
+    },
+    "is-arguments": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz",
+      "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==",
       "dev": true,
       "requires": {
-        "rollup": "^1.31.1"
-      },
-      "dependencies": {
-        "rollup": {
-          "version": "1.32.1",
-          "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz",
-          "integrity": "sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==",
-          "dev": true,
-          "requires": {
-            "@types/estree": "*",
-            "@types/node": "*",
-            "acorn": "^7.1.0"
-          }
-        }
+        "call-bind": "^1.0.0"
       }
     },
-    "is-arguments": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
-      "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
-      "dev": true
-    },
     "is-arrayish": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
       "dev": true
     },
     "is-bigint": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz",
-      "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz",
+      "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==",
       "dev": true
     },
     "is-boolean-attribute": {
       "dev": true
     },
     "is-boolean-object": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz",
-      "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==",
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz",
+      "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.0"
+        "call-bind": "^1.0.2"
+      },
+      "dependencies": {
+        "call-bind": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+          "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "get-intrinsic": "^1.0.2"
+          }
+        },
+        "get-intrinsic": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+          "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "has": "^1.0.3",
+            "has-symbols": "^1.0.1"
+          }
+        }
       }
     },
     "is-buffer": {
       }
     },
     "is-core-module": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz",
-      "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==",
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz",
+      "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==",
       "dev": true,
       "requires": {
         "has": "^1.0.3"
       "dev": true
     },
     "is-docker": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
-      "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+      "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
       "dev": true
     },
     "is-es2016-keyword": {
       "dev": true
     },
     "is-generator-function": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz",
-      "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==",
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.9.tgz",
+      "integrity": "sha512-ZJ34p1uvIfptHCN7sFTjGibB9/oBg17sHqzDLfuwhvmN/qLVvIQXRQ8licZQ35WJ8KuEQt/etnnzQFI9C9Ue/A==",
       "dev": true
     },
     "is-glob": {
       "dev": true
     },
     "is-number-object": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz",
-      "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==",
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz",
+      "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==",
       "dev": true
     },
     "is-obj": {
       "dev": true
     },
     "is-regex": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
-      "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz",
+      "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==",
       "dev": true,
       "requires": {
-        "has-symbols": "^1.0.1"
+        "call-bind": "^1.0.2",
+        "has-symbols": "^1.0.2"
+      },
+      "dependencies": {
+        "call-bind": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+          "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "get-intrinsic": "^1.0.2"
+          }
+        },
+        "get-intrinsic": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+          "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "has": "^1.0.3",
+            "has-symbols": "^1.0.1"
+          }
+        },
+        "has-symbols": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
+          "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
+          "dev": true
+        }
       }
     },
     "is-retry-allowed": {
       "dev": true
     },
     "is-string": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
-      "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==",
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz",
+      "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==",
       "dev": true
     },
     "is-symbol": {
       }
     },
     "is-typed-array": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.3.tgz",
-      "integrity": "sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==",
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.5.tgz",
+      "integrity": "sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug==",
       "dev": true,
       "requires": {
-        "available-typed-arrays": "^1.0.0",
-        "es-abstract": "^1.17.4",
+        "available-typed-arrays": "^1.0.2",
+        "call-bind": "^1.0.2",
+        "es-abstract": "^1.18.0-next.2",
         "foreach": "^2.0.5",
         "has-symbols": "^1.0.1"
+      },
+      "dependencies": {
+        "call-bind": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+          "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "get-intrinsic": "^1.0.2"
+          }
+        },
+        "get-intrinsic": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+          "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "has": "^1.0.3",
+            "has-symbols": "^1.0.1"
+          }
+        }
       }
     },
     "is-typedarray": {
       "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
       "dev": true
     },
+    "is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true
+    },
     "is-utf8": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
       "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=",
       "dev": true
     },
+    "json-parse-better-errors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+      "dev": true
+    },
     "json-schema": {
       "version": "0.2.3",
       "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
       }
     },
     "lodash": {
-      "version": "4.17.19",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
-      "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
       "dev": true
     },
     "lodash.clonedeep": {
       "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
       "dev": true
     },
-    "lodash.flatten": {
-      "version": "4.4.0",
-      "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
-      "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=",
-      "dev": true
-    },
     "lodash.memoize": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
       "dev": true
     },
     "log-symbols": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
-      "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
       "dev": true,
       "requires": {
-        "chalk": "^4.0.0"
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
       },
       "dependencies": {
         "ansi-styles": {
           }
         },
         "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
-          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
+          "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
       },
       "dependencies": {
         "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
           "dev": true
         }
       }
       "dev": true
     },
     "ml-array-max": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/ml-array-max/-/ml-array-max-1.2.0.tgz",
-      "integrity": "sha512-3UH7XCdjINxbtBWj1EuHMeI242Q3uLuC4rTpSybBWUpGjnG/BefAFxmTolUCuXDM59mJ/G/re80CQbaVIuMjQA==",
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/ml-array-max/-/ml-array-max-1.2.3.tgz",
+      "integrity": "sha512-49YwnLlAf4/E/VyezUz+SNfSBhPE8JTahxRPuyM9S9Uv+ft5x0C8A4trtkDgrttMxoxbhudTA1yg8zgJZaYtpA==",
       "dev": true,
       "requires": {
-        "is-any-array": "^0.1.0"
+        "is-any-array": "^1.0.0"
       }
     },
     "ml-array-min": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/ml-array-min/-/ml-array-min-1.2.0.tgz",
-      "integrity": "sha512-Wgf2+lCndLy1SbeOZSUqlkxD9T1CXPT7CIlNGAZRRQI35wsqvfuNtLNH4qKFx8kNjlq3VGXKOSBHeiXR31vaTA==",
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/ml-array-min/-/ml-array-min-1.2.2.tgz",
+      "integrity": "sha512-yidQcOHFaGEuVr6FcwAn+QvKXJv1Lxel5fyKrO+aXGJGp97Mt+p8r21WYtikS/PTVbxdSrliQ0UK4wSHYHHgzQ==",
       "dev": true,
       "requires": {
-        "is-any-array": "^0.1.0"
+        "is-any-array": "^1.0.0"
       }
     },
     "ml-array-rescale": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/ml-array-rescale/-/ml-array-rescale-1.3.2.tgz",
-      "integrity": "sha512-kiXwdVCGrer7rLnjR6Q9ZgP6e9rbnmQvYVUMLXyqNg4+zOs+jek8yBupqPZPDr+NvlSE5OuMnfAbP1oA63kHBA==",
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/ml-array-rescale/-/ml-array-rescale-1.3.5.tgz",
+      "integrity": "sha512-czK+faN7kYrF48SgVQeXGkxUjDEas6BA4EzF4jJNh8UEtzpSvHW3RllZCJCCyrAqeFc+Y/LhgYUzuHFpevM3qA==",
       "dev": true,
       "requires": {
-        "is-any-array": "^0.1.0",
-        "ml-array-max": "^1.2.0",
-        "ml-array-min": "^1.2.0"
+        "is-any-array": "^1.0.0",
+        "ml-array-max": "^1.2.3",
+        "ml-array-min": "^1.2.2"
       }
     },
     "ml-distance-euclidean": {
       }
     },
     "nanoid": {
-      "version": "3.1.18",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.18.tgz",
-      "integrity": "sha512-rndlDjbbHbcV3xi+R2fpJ+PbGMdfBxz5v1fATIQFq0DP64FsicQdwnKLy47K4kZHdRpmQXtz24eGsxQqamzYTA==",
+      "version": "3.1.23",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
+      "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
       "dev": true
     },
     "natural-compare": {
         "lower-case": "^1.1.1"
       }
     },
+    "node-clinic-heap-profiler": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/node-clinic-heap-profiler/-/node-clinic-heap-profiler-1.0.0.tgz",
+      "integrity": "sha512-MwUKAoc6pr93PTkKR0HjtE9ryyXqb7bwxWaZ7PiN2PJHvSH08f9oORLznBVp/JvF0+tt3p2Otu0KW+TeyG5sBQ==",
+      "dev": true,
+      "requires": {
+        "@nearform/clinic-common": "^6.0.0",
+        "@nearform/heap-profiler": "^2.0.0",
+        "abort-controller": "^3.0.0",
+        "copy-to-clipboard": "^3.0.8",
+        "d3-array": "^2.0.2",
+        "d3-fg": "^6.13.1",
+        "d3-selection": "^1.3.2",
+        "fs-extra": "^9.0.1",
+        "lodash.debounce": "^4.0.8",
+        "on-net-listen": "1.1.2",
+        "pump": "^3.0.0",
+        "querystringify": "^2.1.0",
+        "sinusoidal-decimal": "^1.0.0"
+      },
+      "dependencies": {
+        "fs-extra": {
+          "version": "9.1.0",
+          "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+          "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+          "dev": true,
+          "requires": {
+            "at-least-node": "^1.0.0",
+            "graceful-fs": "^4.2.0",
+            "jsonfile": "^6.0.1",
+            "universalify": "^2.0.0"
+          }
+        },
+        "graceful-fs": {
+          "version": "4.2.6",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
+          "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==",
+          "dev": true
+        },
+        "jsonfile": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+          "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.6",
+            "universalify": "^2.0.0"
+          }
+        },
+        "universalify": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+          "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+          "dev": true
+        }
+      }
+    },
     "node-emoji": {
       "version": "1.10.0",
       "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
         "validate-npm-package-license": "^3.0.1"
       }
     },
+    "normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+      "dev": true,
+      "requires": {
+        "remove-trailing-separator": "^1.0.1"
+      }
+    },
     "normalize-url": {
       "version": "4.5.0",
       "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
       "integrity": "sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ=="
     },
     "object-inspect": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
-      "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
+      "version": "1.10.3",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
+      "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==",
       "dev": true
     },
     "object-keys": {
             "get-intrinsic": "^1.0.2"
           }
         },
-        "es-abstract": {
-          "version": "1.18.0",
-          "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz",
-          "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "es-to-primitive": "^1.2.1",
-            "function-bind": "^1.1.1",
-            "get-intrinsic": "^1.1.1",
-            "has": "^1.0.3",
-            "has-symbols": "^1.0.2",
-            "is-callable": "^1.2.3",
-            "is-negative-zero": "^2.0.1",
-            "is-regex": "^1.1.2",
-            "is-string": "^1.0.5",
-            "object-inspect": "^1.9.0",
-            "object-keys": "^1.1.1",
-            "object.assign": "^4.1.2",
-            "string.prototype.trimend": "^1.0.4",
-            "string.prototype.trimstart": "^1.0.4",
-            "unbox-primitive": "^1.0.0"
-          },
-          "dependencies": {
-            "has-symbols": {
-              "version": "1.0.2",
-              "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
-              "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
-              "dev": true
-            }
-          }
-        },
         "get-intrinsic": {
           "version": "1.1.1",
           "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
             "has": "^1.0.3",
             "has-symbols": "^1.0.1"
           }
-        },
-        "is-callable": {
-          "version": "1.2.3",
-          "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz",
-          "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==",
-          "dev": true
-        },
-        "is-regex": {
-          "version": "1.1.2",
-          "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz",
-          "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "has-symbols": "^1.0.1"
-          }
-        },
-        "object-inspect": {
-          "version": "1.9.0",
-          "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz",
-          "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==",
-          "dev": true
-        },
-        "string.prototype.trimend": {
-          "version": "1.0.4",
-          "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
-          "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "define-properties": "^1.1.3"
-          }
-        },
-        "string.prototype.trimstart": {
-          "version": "1.0.4",
-          "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
-          "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
-          "dev": true,
-          "requires": {
-            "call-bind": "^1.0.2",
-            "define-properties": "^1.1.3"
-          }
         }
       }
     },
       }
     },
     "open": {
-      "version": "7.3.0",
-      "resolved": "https://registry.npmjs.org/open/-/open-7.3.0.tgz",
-      "integrity": "sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw==",
+      "version": "7.4.2",
+      "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
+      "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
       "dev": true,
       "requires": {
         "is-docker": "^2.0.0",
       }
     },
     "ora": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/ora/-/ora-5.1.0.tgz",
-      "integrity": "sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w==",
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.0.tgz",
+      "integrity": "sha512-1StwyXQGoU6gdjYkyVcqOLnVlbKj+6yPNNOxJVgpt9t4eksKjiriiHuxktLYkgllwk+D6MbC4ihH84L1udRXPg==",
       "dev": true,
       "requires": {
+        "bl": "^4.1.0",
         "chalk": "^4.1.0",
         "cli-cursor": "^3.1.0",
-        "cli-spinners": "^2.4.0",
+        "cli-spinners": "^2.5.0",
         "is-interactive": "^1.0.0",
-        "log-symbols": "^4.0.0",
-        "mute-stream": "0.0.8",
+        "is-unicode-supported": "^0.1.0",
+        "log-symbols": "^4.1.0",
         "strip-ansi": "^6.0.0",
         "wcwidth": "^1.0.1"
       },
             "color-convert": "^2.0.1"
           }
         },
-        "chalk": {
+        "bl": {
           "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
-          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+          "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+          "dev": true,
+          "requires": {
+            "buffer": "^5.5.0",
+            "inherits": "^2.0.4",
+            "readable-stream": "^3.4.0"
+          }
+        },
+        "buffer": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+          "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+          "dev": true,
+          "requires": {
+            "base64-js": "^1.3.1",
+            "ieee754": "^1.1.13"
+          }
+        },
+        "chalk": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
+          "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
           "dev": true
         },
+        "inherits": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+          "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+          "dev": true
+        },
         "mimic-fn": {
           "version": "2.1.0",
           "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
           "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
           "dev": true
         },
-        "mute-stream": {
-          "version": "0.0.8",
-          "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
-          "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
-          "dev": true
-        },
         "onetime": {
           "version": "5.1.2",
           "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
             "mimic-fn": "^2.1.0"
           }
         },
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        },
         "restore-cursor": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
       "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=",
       "dev": true
     },
+    "path-starts-with": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/path-starts-with/-/path-starts-with-1.0.0.tgz",
+      "integrity": "sha1-soJDAV6LE43lcmgqxS2kLmRq2E4=",
+      "dev": true,
+      "requires": {
+        "normalize-path": "^2.1.1"
+      }
+    },
     "path-type": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
       "dev": true
     },
     "pbkdf2": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
-      "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+      "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
       "dev": true,
       "requires": {
         "create-hash": "^1.1.2",
       }
     },
     "poolifier": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/poolifier/-/poolifier-2.0.1.tgz",
-      "integrity": "sha512-klkLv35QVumXKrQj6Totvwqb0lw34j7mIsEm8uZXXHlcpVCvnhhgVFVyuZUOSNTjZnBCaiB0KcLos03cqj38CA=="
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/poolifier/-/poolifier-2.0.2.tgz",
+      "integrity": "sha512-qibRFXZlhYJYf/jIoayoOb31S8EeMDF89H9ujOQh1xOxLreYZ0EzCEnnOR8OdpdAxyl+JKyt7sgFLHK78WTV5w=="
     },
     "postcss": {
-      "version": "8.1.10",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.1.10.tgz",
-      "integrity": "sha512-iBXEV5VTTYaRRdxiFYzTtuv2lGMQBExqkZKSzkJe+Fl6rvQrA/49UVGKqB+LG54hpW/TtDBMGds8j33GFNW7pg==",
+      "version": "8.2.15",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.15.tgz",
+      "integrity": "sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q==",
       "dev": true,
       "requires": {
-        "colorette": "^1.2.1",
-        "nanoid": "^3.1.18",
-        "source-map": "^0.6.1",
-        "vfile-location": "^3.2.0"
+        "colorette": "^1.2.2",
+        "nanoid": "^3.1.23",
+        "source-map": "^0.6.1"
       },
       "dependencies": {
+        "colorette": {
+          "version": "1.2.2",
+          "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
+          "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==",
+          "dev": true
+        },
         "source-map": {
           "version": "0.6.1",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
       "dev": true
     },
     "pretty-bytes": {
-      "version": "5.4.1",
-      "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.4.1.tgz",
-      "integrity": "sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==",
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
+      "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==",
       "dev": true
     },
     "pretty-hrtime": {
       }
     },
     "protocol-buffers-schema": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.4.0.tgz",
-      "integrity": "sha512-G/2kcamPF2S49W5yaMGdIpkG6+5wZF0fzBteLKgEHjbNzqjZQ85aAs1iJGto31EJaSTkNvHs5IXuHSaTLWBAiA==",
+      "version": "3.5.1",
+      "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.5.1.tgz",
+      "integrity": "sha512-YVCvdhxWNDP8/nJDyXLuM+UFsuPk4+1PB7WGPVDzm3HTHbzFLxQYeW2iZpS4mmnXrQJGBzt230t/BbEb7PrQaw==",
       "dev": true
     },
     "pseudomap": {
       },
       "dependencies": {
         "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
           "dev": true
         }
       }
       "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=",
       "dev": true
     },
+    "remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+      "dev": true
+    },
     "repeating": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
       }
     },
     "rollup": {
-      "version": "2.45.2",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.45.2.tgz",
-      "integrity": "sha512-kRRU7wXzFHUzBIv0GfoFFIN3m9oteY4uAsKllIpQDId5cfnkWF2J130l+27dzDju0E6MScKiV0ZM5Bw8m4blYQ==",
+      "version": "2.48.0",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.48.0.tgz",
+      "integrity": "sha512-wl9ZSSSsi5579oscSDYSzGn092tCS076YB+TQrzsGuSfYyJeep8eEWj0eaRjuC5McuMNmcnR8icBqiE/FWNB1A==",
       "dev": true,
       "requires": {
         "fsevents": "~2.3.1"
         "tslib": "2.1.0"
       },
       "dependencies": {
-        "is-core-module": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
-          "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
-          "dev": true,
-          "requires": {
-            "has": "^1.0.3"
-          }
-        },
         "resolve": {
           "version": "1.20.0",
           "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
       "dev": true
     },
     "rxjs": {
-      "version": "6.6.3",
-      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
-      "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
+      "version": "6.6.7",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+      "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
       "dev": true,
       "requires": {
         "tslib": "^1.9.0"
         }
       }
     },
+    "sonic-boom": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz",
+      "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==",
+      "dev": true,
+      "requires": {
+        "atomic-sleep": "^1.0.0",
+        "flatstr": "^1.0.12"
+      }
+    },
     "source-map": {
       "version": "0.5.7",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
       }
     },
     "stream-http": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.1.1.tgz",
-      "integrity": "sha512-S7OqaYu0EkFpgeGFb/NPOoPLxFko7TPqtEeFg5DXPB4v/KETHG0Ln6fRFrNezoelpaDKmycEmmZ81cC9DAwgYg==",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz",
+      "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==",
       "dev": true,
       "requires": {
         "builtin-status-codes": "^3.0.0",
       }
     },
     "string.prototype.trimend": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz",
-      "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
+      "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.0",
+        "call-bind": "^1.0.2",
         "define-properties": "^1.1.3"
+      },
+      "dependencies": {
+        "call-bind": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+          "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "get-intrinsic": "^1.0.2"
+          }
+        },
+        "get-intrinsic": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+          "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "has": "^1.0.3",
+            "has-symbols": "^1.0.1"
+          }
+        }
       }
     },
     "string.prototype.trimstart": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz",
-      "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
+      "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
       "dev": true,
       "requires": {
-        "call-bind": "^1.0.0",
+        "call-bind": "^1.0.2",
         "define-properties": "^1.1.3"
+      },
+      "dependencies": {
+        "call-bind": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+          "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "get-intrinsic": "^1.0.2"
+          }
+        },
+        "get-intrinsic": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+          "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+          "dev": true,
+          "requires": {
+            "function-bind": "^1.1.1",
+            "has": "^1.0.3",
+            "has-symbols": "^1.0.1"
+          }
+        }
       }
     },
     "string_decoder": {
       }
     },
     "table": {
-      "version": "6.0.9",
-      "resolved": "https://registry.npmjs.org/table/-/table-6.0.9.tgz",
-      "integrity": "sha512-F3cLs9a3hL1Z7N4+EkSscsel3z55XT950AvB05bwayrNg5T1/gykXtigioTAjbltvbMSJvvhFCbnf6mX+ntnJQ==",
+      "version": "6.7.0",
+      "resolved": "https://registry.npmjs.org/table/-/table-6.7.0.tgz",
+      "integrity": "sha512-SAM+5p6V99gYiiy2gT5ArdzgM1dLDed0nkrWmG6Fry/bUS/m9x83BwpJUOf1Qj/x2qJd+thL6IkIx7qPGRxqBw==",
       "dev": true,
       "requires": {
         "ajv": "^8.0.1",
-        "is-boolean-object": "^1.1.0",
-        "is-number-object": "^1.0.4",
-        "is-string": "^1.0.5",
         "lodash.clonedeep": "^4.5.0",
-        "lodash.flatten": "^4.4.0",
         "lodash.truncate": "^4.4.2",
         "slice-ansi": "^4.0.0",
-        "string-width": "^4.2.0"
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0"
       },
       "dependencies": {
         "ajv": {
-          "version": "8.0.5",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.0.5.tgz",
-          "integrity": "sha512-RkiLa/AeJx7+9OvniQ/qeWu0w74A8DiPPBclQ6ji3ZQkv5KamO+QGpqmi7O4JIw3rHGUXZ6CoP9tsAkn3gyazg==",
+          "version": "8.2.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.2.0.tgz",
+          "integrity": "sha512-WSNGFuyWd//XO8n/m/EaOlNLtO0yL8EXT/74LqT4khdhpZjP7lkj/kT5uwRmGitKEVp/Oj7ZUHeGfPtgHhQ5CA==",
           "dev": true,
           "requires": {
             "fast-deep-equal": "^3.1.1",
       }
     },
     "utf-8-validate": {
-      "version": "5.0.4",
-      "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.4.tgz",
-      "integrity": "sha512-MEF05cPSq3AwJ2C7B7sHAA6i53vONoZbMGX8My5auEVm6W+dJ2Jd/TZPyGJ5CH42V2XtbI5FD28HeHeqlPzZ3Q==",
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.5.tgz",
+      "integrity": "sha512-+pnxRYsS/axEpkrrEpzYfNZGXp0IjC/9RIxwM5gntY4Koi8SHmUGSfxfWqxZdRxrtaoVstuOzUp/rbs3JSPELQ==",
       "optional": true,
       "requires": {
         "node-gyp-build": "^4.2.0"
         "extsprintf": "^1.2.0"
       }
     },
-    "vfile-location": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz",
-      "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==",
-      "dev": true
-    },
     "vm-browserify": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
       }
     },
     "which-typed-array": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.2.tgz",
-      "integrity": "sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==",
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.4.tgz",
+      "integrity": "sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==",
       "dev": true,
       "requires": {
         "available-typed-arrays": "^1.0.2",
-        "es-abstract": "^1.17.5",
+        "call-bind": "^1.0.0",
+        "es-abstract": "^1.18.0-next.1",
         "foreach": "^2.0.5",
         "function-bind": "^1.1.1",
         "has-symbols": "^1.0.1",
       }
     },
     "winston-daily-rotate-file": {
-      "version": "4.5.2",
-      "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-4.5.2.tgz",
-      "integrity": "sha512-DpAz9djExzFGVGRIKCKzsjOQaIINbjOUJ8CRsZGz0SQOMMcO1kM7jqTdzQAM9CRTEksZV9bBw9TT0ddQBGxs9g==",
+      "version": "4.5.5",
+      "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-4.5.5.tgz",
+      "integrity": "sha512-ds0WahIjiDhKCiMXmY799pDBW+58ByqIBtUcsqr4oDoXrAI3Zn+hbgFdUxzMfqA93OG0mPLYVMiotqTgE/WeWQ==",
       "requires": {
         "file-stream-rotator": "^0.5.7",
         "object-hash": "^2.0.1",
       }
     },
     "ws": {
-      "version": "7.4.4",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
-      "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
+      "version": "7.4.5",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz",
+      "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g=="
     },
     "xdg-basedir": {
       "version": "3.0.0",
index b244b9963b11c26fd45496f8b0878b8f3fcc9917..27af082df9824e634e3240907bfa6344894652c9 100644 (file)
   },
   "dependencies": {
     "mongodb": "^3.6.6",
-    "poolifier": "^2.0.1",
+    "poolifier": "^2.0.2",
     "source-map-support": "^0.5.19",
     "tslib": "^2.2.0",
     "uuid": "^8.3.2",
     "winston": "^3.3.3",
-    "winston-daily-rotate-file": "^4.5.2",
-    "ws": "^7.4.4"
+    "winston-daily-rotate-file": "^4.5.5",
+    "ws": "^7.4.5"
   },
   "optionalDependencies": {
     "bufferutil": "^4.0.3",
-    "utf-8-validate": "^5.0.4"
+    "utf-8-validate": "^5.0.5"
   },
   "devDependencies": {
-    "@types/node": "^14.14.37",
+    "@types/node": "^14.14.45",
     "@types/uuid": "^8.3.0",
-    "@types/ws": "^7.4.1",
-    "@typescript-eslint/eslint-plugin": "^4.22.0",
-    "@typescript-eslint/parser": "^4.22.0",
-    "clinic": "^8.0.1",
+    "@types/ws": "^7.4.4",
+    "@typescript-eslint/eslint-plugin": "^4.24.0",
+    "@typescript-eslint/parser": "^4.24.0",
+    "clinic": "^9.0.0",
     "cross-env": "^7.0.3",
-    "eslint": "^7.24.0",
-    "eslint-plugin-import": "^2.22.1",
-    "eslint-plugin-jsdoc": "^32.3.0",
+    "eslint": "^7.26.0",
+    "eslint-plugin-import": "^2.23.2",
+    "eslint-plugin-jsdoc": "^34.7.0",
     "mbt": "^1.1.1",
     "npm-check": "^5.9.2",
-    "rollup": "^2.45.2",
+    "rollup": "^2.48.0",
     "rollup-plugin-analyzer": "^4.0.0",
     "rollup-plugin-copy": "^3.4.0",
     "rollup-plugin-delete": "^2.0.0",
index 316f8b3eac6df74351d7e31d12e80d496361ff08..b11a543f83c3fa9b7f170efe54a3b08856876809 100644 (file)
@@ -8,7 +8,7 @@
   "power": 50000,
   "powerSharedByConnectors": true,
   "powerUnit": "W",
-  "powerOutType": "DC",
+  "currentOutType": "DC",
   "useConnectorId0": true,
   "randomConnectors": false,
   "resetTime": 60,
index 3f743f966537f473db87b9c88af59c2be4d6a9a5..0ba61ec62ed46db772e8aa14c5979f516dcb1bbd 100644 (file)
@@ -7,7 +7,7 @@
   "power": 50000,
   "powerSharedByConnectors": true,
   "powerUnit": "W",
-  "powerOutType": "DC",
+  "currentOutType": "DC",
   "numberOfConnectors": 2,
   "useConnectorId0": true,
   "randomConnectors": false,
index 0da43ac6de86c80489071b3ffdf84ab3a4dba53a..a695e2bd999c051fe679a5988226d9fd8acaed76 100644 (file)
@@ -6,7 +6,7 @@
   "power": 75000,
   "powerUnit": "W",
   "powerSharedByConnectors": true,
-  "powerOutType": "DC",
+  "currentOutType": "DC",
   "numberOfConnectors": 3,
   "randomConnectors": false,
   "Configuration": {
index f251d2c4b73448881ae608d879a9cfc8d4d92d06..4af1ab1da97eb4ba46ae0aeb0d8f7aa397a0fec0 100644 (file)
@@ -6,7 +6,7 @@
   "power": 50000,
   "powerUnit": "W",
   "powerSharedByConnectors": true,
-  "powerOutType": "DC",
+  "currentOutType": "DC",
   "numberOfConnectors": 3,
   "randomConnectors": false,
   "Configuration": {
index 8cb63eb6967684086bfba8e6cb5a034efd37c748..0a713610b6ab0e60d9ccadfa018fe55f91c11f28 100644 (file)
@@ -6,7 +6,7 @@
   "power": 50000,
   "powerUnit": "W",
   "powerSharedByConnectors": true,
-  "powerOutType": "DC",
+  "currentOutType": "DC",
   "numberOfConnectors": 9,
   "randomConnectors": false,
   "Configuration": {
index bb8d75b3ecaacbc06095c73e8216f395915b231e..0562a8973bb8bd36a60f6353e6503339e6111a63 100644 (file)
@@ -9,7 +9,7 @@ import logger from '../utils/Logger';
 export default class AutomaticTransactionGenerator {
   public timeToStop: boolean;
   private chargingStation: ChargingStation;
-  private performanceObserver: PerformanceObserver;
+  private performanceObserver!: PerformanceObserver;
 
   constructor(chargingStation: ChargingStation) {
     this.chargingStation = chargingStation;
@@ -17,7 +17,7 @@ export default class AutomaticTransactionGenerator {
     if (this.chargingStation.getEnableStatistics()) {
       this.performanceObserver = new PerformanceObserver((list) => {
         const entry = list.getEntries()[0];
-        this.chargingStation.statistics.logPerformance(entry, Constants.ENTITY_AUTOMATIC_TRANSACTION_GENERATOR);
+        this.chargingStation.performanceStatistics.logPerformance(entry, Constants.ENTITY_AUTOMATIC_TRANSACTION_GENERATOR);
         this.performanceObserver.disconnect();
       });
     }
@@ -53,7 +53,7 @@ export default class AutomaticTransactionGenerator {
     this.timeToStop = true;
   }
 
-  public async startConnector(connectorId: number): Promise<void> {
+  private async startConnector(connectorId: number): Promise<void> {
     do {
       if (this.timeToStop) {
         logger.error(this.logPrefix(connectorId) + ' Entered in transaction loop while a request to stop it was made');
@@ -96,7 +96,7 @@ export default class AutomaticTransactionGenerator {
           startResponse = await this.startTransaction(connectorId, this);
         }
         if (startResponse?.idTagInfo?.status !== AuthorizationStatus.ACCEPTED) {
-          logger.info(this.logPrefix(connectorId) + ' transaction rejected');
+          logger.warn(this.logPrefix(connectorId) + ' transaction rejected');
           await Utils.sleep(Constants.CHARGING_STATION_ATG_WAIT_TIME);
         } else {
           // Wait until end of transaction
@@ -149,13 +149,14 @@ export default class AutomaticTransactionGenerator {
   // eslint-disable-next-line consistent-this
   private async stopTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise<StopTransactionResponse> {
     const transactionId = self.chargingStation.getConnector(connectorId).transactionId;
-    return await self.chargingStation.ocppRequestService.sendStopTransaction(transactionId, self.chargingStation.getTransactionMeterStop(transactionId), self.chargingStation.getTransactionIdTag(transactionId));
+    return await self.chargingStation.ocppRequestService.sendStopTransaction(transactionId, self.chargingStation.getTransactionMeterStop(transactionId),
+      self.chargingStation.getTransactionIdTag(transactionId));
   }
 
-  private logPrefix(connectorId: number = null): string {
+  private logPrefix(connectorId?: number): string {
     if (connectorId) {
-      return Utils.logPrefix(' ' + this.chargingStation.stationInfo.chargingStationId + ' ATG on connector #' + connectorId.toString() + ':');
+      return Utils.logPrefix(' ' + this.chargingStation.stationInfo.chargingStationId + ' ATG on connector #' + connectorId.toString() + ':');
     }
-    return Utils.logPrefix(' ' + this.chargingStation.stationInfo.chargingStationId + ' ATG:');
+    return Utils.logPrefix(' ' + this.chargingStation.stationInfo.chargingStationId + ' ATG:');
   }
 }
index ddf21f48bb61721686bb81c45d2a23424fdd2330..a6eb4939cf4f6cd0bf612362fbbc6744cd0cd53b 100644 (file)
@@ -10,7 +10,7 @@ export default class Bootstrap {
   private static instance: Bootstrap;
   private started: boolean;
   private workerScript: string;
-  private workerImplementationInstance: WorkerAbstract;
+  private workerImplementationInstance: WorkerAbstract | null = null;
 
   private constructor() {
     this.started = false;
@@ -29,7 +29,7 @@ export default class Bootstrap {
     if (isMainThread && !this.started) {
       try {
         let numStationsTotal = 0;
-        await this.getWorkerImplementationInstance().start();
+        await this.getWorkerImplementationInstance()?.start();
         // Start ChargingStation object in worker thread
         if (Configuration.getStationTemplateURLs()) {
           for (const stationURL of Configuration.getStationTemplateURLs()) {
@@ -40,7 +40,7 @@ export default class Bootstrap {
                   index,
                   templateFile: path.join(path.resolve(__dirname, '../'), 'assets', 'station-templates', path.basename(stationURL.file))
                 };
-                await this.getWorkerImplementationInstance().addElement(workerData);
+                await this.getWorkerImplementationInstance()?.addElement(workerData);
                 numStationsTotal++;
               }
             } catch (error) {
@@ -64,7 +64,7 @@ export default class Bootstrap {
 
   public async stop(): Promise<void> {
     if (isMainThread && this.started) {
-      await this.getWorkerImplementationInstance().stop();
+      await this.getWorkerImplementationInstance()?.stop();
       // Nullify to force worker implementation instance creation
       this.workerImplementationInstance = null;
     }
@@ -76,13 +76,18 @@ export default class Bootstrap {
     await this.start();
   }
 
-  private getWorkerImplementationInstance(): WorkerAbstract {
+  private getWorkerImplementationInstance(): WorkerAbstract | null {
     if (!this.workerImplementationInstance) {
-      this.workerImplementationInstance = WorkerFactory.getWorkerImplementation<StationWorkerData>(this.workerScript, Configuration.getWorkerProcess(), {
-        poolMaxSize: Configuration.getWorkerPoolMaxSize(),
-        poolMinSize: Configuration.getWorkerPoolMinSize(),
-        elementsPerWorker: Configuration.getChargingStationsPerWorker()
-      });
+      this.workerImplementationInstance = WorkerFactory.getWorkerImplementation<StationWorkerData>(this.workerScript, Configuration.getWorkerProcess(),
+        {
+          startDelay: Configuration.getWorkerStartDelay(),
+          poolMaxSize: Configuration.getWorkerPoolMaxSize(),
+          poolMinSize: Configuration.getWorkerPoolMinSize(),
+          elementsPerWorker: Configuration.getChargingStationsPerWorker(),
+          poolOptions: {
+            workerChoiceStrategy: Configuration.getWorkerPoolStrategy()
+          }
+        });
     }
     return this.workerImplementationInstance;
   }
index 15cac9b530875089e1e83d995ae0985bd7e4aa05..ff912e97d36c95eb3220c2743c506b9ad6f62a36 100644 (file)
@@ -1,6 +1,6 @@
 import { BootNotificationResponse, RegistrationStatus } from '../types/ocpp/Responses';
 import ChargingStationConfiguration, { ConfigurationKey } from '../types/ChargingStationConfiguration';
-import ChargingStationTemplate, { PowerOutType, VoltageOut } from '../types/ChargingStationTemplate';
+import ChargingStationTemplate, { CurrentOutType, VoltageOut } from '../types/ChargingStationTemplate';
 import Connectors, { Connector } from '../types/Connectors';
 import { PerformanceObserver, performance } from 'perf_hooks';
 import Requests, { AvailabilityType, BootNotificationRequest, IncomingRequest, IncomingRequestCommand } from '../types/ocpp/Requests';
@@ -21,8 +21,8 @@ import OCPPError from './OcppError';
 import OCPPIncomingRequestService from './ocpp/OCPPIncomingRequestService';
 import OCPPRequestService from './ocpp/OCPPRequestService';
 import { OCPPVersion } from '../types/ocpp/OCPPVersion';
+import PerformanceStatistics from '../utils/PerformanceStatistics';
 import { StandardParametersKey } from '../types/ocpp/Configuration';
-import Statistics from '../utils/Statistics';
 import { StopTransactionReason } from '../types/ocpp/Transaction';
 import Utils from '../utils/Utils';
 import { WebSocketCloseEventStatusCode } from '../types/WebSocket';
@@ -34,28 +34,28 @@ import path from 'path';
 export default class ChargingStation {
   public stationTemplateFile: string;
   public authorizedTags: string[];
-  public stationInfo: ChargingStationInfo;
+  public stationInfo!: ChargingStationInfo;
   public connectors: Connectors;
-  public configuration: ChargingStationConfiguration;
+  public configuration!: ChargingStationConfiguration;
   public hasStopped: boolean;
-  public wsConnection: WebSocket;
+  public wsConnection!: WebSocket;
   public requests: Requests;
   public messageQueue: string[];
-  public statistics: Statistics;
-  public heartbeatSetInterval: NodeJS.Timeout;
-  public ocppIncomingRequestService: OCPPIncomingRequestService;
-  public ocppRequestService: OCPPRequestService;
+  public performanceStatistics!: PerformanceStatistics;
+  public heartbeatSetInterval!: NodeJS.Timeout;
+  public ocppIncomingRequestService!: OCPPIncomingRequestService;
+  public ocppRequestService!: OCPPRequestService;
   private index: number;
-  private bootNotificationRequest: BootNotificationRequest;
-  private bootNotificationResponse: BootNotificationResponse;
-  private connectorsConfigurationHash: string;
-  private supervisionUrl: string;
-  private wsConnectionUrl: string;
+  private bootNotificationRequest!: BootNotificationRequest;
+  private bootNotificationResponse!: BootNotificationResponse | null;
+  private connectorsConfigurationHash!: string;
+  private supervisionUrl!: string;
+  private wsConnectionUrl!: string;
   private hasSocketRestarted: boolean;
   private autoReconnectRetryCount: number;
-  private automaticTransactionGeneration: AutomaticTransactionGenerator;
-  private performanceObserver: PerformanceObserver;
-  private webSocketPingSetInterval: NodeJS.Timeout;
+  private automaticTransactionGeneration!: AutomaticTransactionGenerator;
+  private performanceObserver!: PerformanceObserver;
+  private webSocketPingSetInterval!: NodeJS.Timeout;
 
   constructor(index: number, stationTemplateFile: string) {
     this.index = index;
@@ -74,7 +74,7 @@ export default class ChargingStation {
   }
 
   public logPrefix(): string {
-    return Utils.logPrefix(` ${this.stationInfo.chargingStationId}:`);
+    return Utils.logPrefix(` ${this.stationInfo.chargingStationId} |`);
   }
 
   public getRandomTagId(): string {
@@ -86,15 +86,15 @@ export default class ChargingStation {
     return !Utils.isEmptyArray(this.authorizedTags);
   }
 
-  public getEnableStatistics(): boolean {
+  public getEnableStatistics(): boolean | undefined {
     return !Utils.isUndefined(this.stationInfo.enableStatistics) ? this.stationInfo.enableStatistics : true;
   }
 
-  public getNumberOfPhases(): number {
-    switch (this.getPowerOutType()) {
-      case PowerOutType.AC:
+  public getNumberOfPhases(): number | undefined {
+    switch (this.getCurrentOutType()) {
+      case CurrentOutType.AC:
         return !Utils.isUndefined(this.stationInfo.numberOfPhases) ? this.stationInfo.numberOfPhases : 3;
-      case PowerOutType.DC:
+      case CurrentOutType.DC:
         return 0;
     }
   }
@@ -119,18 +119,18 @@ export default class ChargingStation {
     return this.connectors[id];
   }
 
-  public getPowerOutType(): PowerOutType {
-    return !Utils.isUndefined(this.stationInfo.powerOutType) ? this.stationInfo.powerOutType : PowerOutType.AC;
+  public getCurrentOutType(): CurrentOutType | undefined {
+    return !Utils.isUndefined(this.stationInfo.currentOutType) ? this.stationInfo.currentOutType : CurrentOutType.AC;
   }
 
-  public getVoltageOut(): number {
-    const errMsg = `${this.logPrefix()} Unknown ${this.getPowerOutType()} powerOutType in template file ${this.stationTemplateFile}, cannot define default voltage out`;
+  public getVoltageOut(): number | undefined {
+    const errMsg = `${this.logPrefix()} Unknown ${this.getCurrentOutType()} currentOutType in template file ${this.stationTemplateFile}, cannot define default voltage out`;
     let defaultVoltageOut: number;
-    switch (this.getPowerOutType()) {
-      case PowerOutType.AC:
+    switch (this.getCurrentOutType()) {
+      case CurrentOutType.AC:
         defaultVoltageOut = VoltageOut.VOLTAGE_230;
         break;
-      case PowerOutType.DC:
+      case CurrentOutType.DC:
         defaultVoltageOut = VoltageOut.VOLTAGE_400;
         break;
       default:
@@ -140,7 +140,7 @@ export default class ChargingStation {
     return !Utils.isUndefined(this.stationInfo.voltageOut) ? this.stationInfo.voltageOut : defaultVoltageOut;
   }
 
-  public getTransactionIdTag(transactionId: number): string {
+  public getTransactionIdTag(transactionId: number): string | undefined {
     for (const connector in this.connectors) {
       if (Utils.convertToInt(connector) > 0 && this.getConnector(Utils.convertToInt(connector)).transactionId === transactionId) {
         return this.getConnector(Utils.convertToInt(connector)).idTag;
@@ -148,7 +148,7 @@ export default class ChargingStation {
     }
   }
 
-  public getTransactionMeterStop(transactionId: number): number {
+  public getTransactionMeterStop(transactionId: number): number | undefined {
     for (const connector in this.connectors) {
       if (Utils.convertToInt(connector) > 0 && this.getConnector(Utils.convertToInt(connector)).transactionId === transactionId) {
         return this.getConnector(Utils.convertToInt(connector)).lastEnergyActiveImportRegisterValue;
@@ -181,7 +181,7 @@ export default class ChargingStation {
       }, this.getHeartbeatInterval());
       logger.info(this.logPrefix() + ' Heartbeat started every ' + Utils.milliSecondsToHHMMSS(this.getHeartbeatInterval()));
     } else if (this.heartbeatSetInterval) {
-      logger.info(this.logPrefix() + ' Heartbeat every ' + Utils.milliSecondsToHHMMSS(this.getHeartbeatInterval()) + ' already started');
+      logger.info(this.logPrefix() + ' Heartbeat already started every ' + Utils.milliSecondsToHHMMSS(this.getHeartbeatInterval()));
     } else {
       logger.error(`${this.logPrefix()} Heartbeat interval set to ${this.getHeartbeatInterval() ? Utils.milliSecondsToHHMMSS(this.getHeartbeatInterval()) : this.getHeartbeatInterval()}, not starting the heartbeat`);
     }
@@ -264,8 +264,8 @@ export default class ChargingStation {
     this.hasStopped = true;
   }
 
-  public getConfigurationKey(key: string | StandardParametersKey, caseInsensitive = false): ConfigurationKey {
-    const configurationKey: ConfigurationKey = this.configuration.configurationKey.find((configElement) => {
+  public getConfigurationKey(key: string | StandardParametersKey, caseInsensitive = false): ConfigurationKey | undefined {
+    const configurationKey: ConfigurationKey | undefined = this.configuration.configurationKey.find((configElement) => {
       if (caseInsensitive) {
         return configElement.key.toLowerCase() === key.toLowerCase();
       }
@@ -301,7 +301,7 @@ export default class ChargingStation {
 
   public setChargingProfile(connectorId: number, cp: ChargingProfile): boolean {
     if (!Utils.isEmptyArray(this.getConnector(connectorId).chargingProfiles)) {
-      this.getConnector(connectorId).chargingProfiles.forEach((chargingProfile: ChargingProfile, index: number) => {
+      this.getConnector(connectorId).chargingProfiles?.forEach((chargingProfile: ChargingProfile, index: number) => {
         if (chargingProfile.chargingProfileId === cp.chargingProfileId
           || (chargingProfile.stackLevel === cp.stackLevel && chargingProfile.chargingProfilePurpose === cp.chargingProfilePurpose)) {
           this.getConnector(connectorId).chargingProfiles[index] = cp;
@@ -309,7 +309,7 @@ export default class ChargingStation {
         }
       });
     }
-    this.getConnector(connectorId).chargingProfiles.push(cp);
+    this.getConnector(connectorId).chargingProfiles?.push(cp);
     return true;
   }
 
@@ -465,10 +465,10 @@ export default class ChargingStation {
     }
     this.stationInfo.powerDivider = this.getPowerDivider();
     if (this.getEnableStatistics()) {
-      this.statistics = new Statistics(this.stationInfo.chargingStationId);
+      this.performanceStatistics = new PerformanceStatistics(this.stationInfo.chargingStationId);
       this.performanceObserver = new PerformanceObserver((list) => {
         const entry = list.getEntries()[0];
-        this.statistics.logPerformance(entry, Constants.ENTITY_CHARGING_STATION);
+        this.performanceStatistics.logPerformance(entry, Constants.ENTITY_CHARGING_STATION);
         this.performanceObserver.disconnect();
       });
     }
@@ -480,7 +480,8 @@ export default class ChargingStation {
       // Send BootNotification
       let registrationRetryCount = 0;
       do {
-        this.bootNotificationResponse = await this.ocppRequestService.sendBootNotification(this.bootNotificationRequest.chargePointModel, this.bootNotificationRequest.chargePointVendor, this.bootNotificationRequest.chargeBoxSerialNumber, this.bootNotificationRequest.firmwareVersion);
+        this.bootNotificationResponse = await this.ocppRequestService.sendBootNotification(this.bootNotificationRequest.chargePointModel,
+          this.bootNotificationRequest.chargePointVendor, this.bootNotificationRequest.chargeBoxSerialNumber, this.bootNotificationRequest.firmwareVersion);
         if (!this.isRegistered()) {
           registrationRetryCount++;
           await Utils.sleep(this.bootNotificationResponse?.interval ? this.bootNotificationResponse.interval * 1000 : Constants.OCPP_DEFAULT_BOOT_NOTIFICATION_INTERVAL);
@@ -500,7 +501,7 @@ export default class ChargingStation {
     this.hasSocketRestarted = false;
   }
 
-  private async onClose(closeEvent): Promise<void> {
+  private async onClose(closeEvent: any): Promise<void> {
     switch (closeEvent) {
       case WebSocketCloseEventStatusCode.CLOSE_NORMAL: // Normal close
       case WebSocketCloseEventStatusCode.CLOSE_NO_STATUS:
@@ -516,7 +517,7 @@ export default class ChargingStation {
 
   private async onMessage(messageEvent: MessageEvent): Promise<void> {
     let [messageType, messageId, commandName, commandPayload, errorDetails]: IncomingRequest = [0, '', '' as IncomingRequestCommand, {}, {}];
-    let responseCallback: (payload?: Record<string, unknown> | string, requestPayload?: Record<string, unknown>) => void;
+    let responseCallback: (payload: Record<string, unknown> | string, requestPayload: Record<string, unknown>) => void;
     let rejectCallback: (error: OCPPError) => void;
     let requestPayload: Record<string, unknown>;
     let errMsg: string;
@@ -529,7 +530,7 @@ export default class ChargingStation {
         // Incoming Message
         case MessageType.CALL_MESSAGE:
           if (this.getEnableStatistics()) {
-            this.statistics.addMessage(commandName, messageType);
+            this.performanceStatistics.addMessage(commandName, messageType);
           }
           // Process the call
           await this.ocppIncomingRequestService.handleRequest(messageId, commandName, commandPayload);
@@ -585,7 +586,7 @@ export default class ChargingStation {
     logger.debug(this.logPrefix() + ' Has received a WS pong (rfc6455) from the server');
   }
 
-  private async onError(errorEvent): Promise<void> {
+  private async onError(errorEvent: any): Promise<void> {
     logger.error(this.logPrefix() + ' Socket error: %j', errorEvent);
     // pragma switch (errorEvent.code) {
     //   case 'ECONNREFUSED':
@@ -598,7 +599,7 @@ export default class ChargingStation {
     return this.stationInfo.Configuration ? this.stationInfo.Configuration : {} as ChargingStationConfiguration;
   }
 
-  private getAuthorizationFile(): string {
+  private getAuthorizationFile(): string | undefined {
     return this.stationInfo.authorizationFile && path.join(path.resolve(__dirname, '../'), 'assets', path.basename(this.stationInfo.authorizationFile));
   }
 
@@ -621,7 +622,7 @@ export default class ChargingStation {
     return authorizedTags;
   }
 
-  private getUseConnectorId0(): boolean {
+  private getUseConnectorId0(): boolean | undefined {
     return !Utils.isUndefined(this.stationInfo.useConnectorId0) ? this.stationInfo.useConnectorId0 : true;
   }
 
@@ -636,7 +637,7 @@ export default class ChargingStation {
   }
 
   // 0 for disabling
-  private getConnectionTimeout(): number {
+  private getConnectionTimeout(): number | undefined {
     if (!Utils.isUndefined(this.stationInfo.connectionTimeout)) {
       return this.stationInfo.connectionTimeout;
     }
@@ -647,7 +648,7 @@ export default class ChargingStation {
   }
 
   // -1 for unlimited, 0 for disabling
-  private getAutoReconnectMaxRetries(): number {
+  private getAutoReconnectMaxRetries(): number | undefined {
     if (!Utils.isUndefined(this.stationInfo.autoReconnectMaxRetries)) {
       return this.stationInfo.autoReconnectMaxRetries;
     }
@@ -658,7 +659,7 @@ export default class ChargingStation {
   }
 
   // 0 for disabling
-  private getRegistrationMaxRetries(): number {
+  private getRegistrationMaxRetries(): number | undefined {
     if (!Utils.isUndefined(this.stationInfo.registrationMaxRetries)) {
       return this.stationInfo.registrationMaxRetries;
     }
@@ -727,11 +728,12 @@ export default class ChargingStation {
         this.automaticTransactionGeneration = new AutomaticTransactionGenerator(this);
       }
       if (this.automaticTransactionGeneration.timeToStop) {
-        await this.automaticTransactionGeneration.start();
+        // The ATG might sleep
+        void this.automaticTransactionGeneration.start();
       }
     }
     if (this.getEnableStatistics()) {
-      this.statistics.start();
+      this.performanceStatistics.start();
     }
   }
 
@@ -774,7 +776,6 @@ export default class ChargingStation {
   private stopWebSocketPing(): void {
     if (this.webSocketPingSetInterval) {
       clearInterval(this.webSocketPingSetInterval);
-      this.webSocketPingSetInterval = null;
     }
   }
 
@@ -793,7 +794,7 @@ export default class ChargingStation {
     return supervisionUrls as string;
   }
 
-  private getHeartbeatInterval(): number {
+  private getHeartbeatInterval(): number | undefined {
     const HeartbeatInterval = this.getConfigurationKey(StandardParametersKey.HeartbeatInterval);
     if (HeartbeatInterval) {
       return Utils.convertToInt(HeartbeatInterval.value) * 1000;
@@ -807,7 +808,6 @@ export default class ChargingStation {
   private stopHeartbeat(): void {
     if (this.heartbeatSetInterval) {
       clearInterval(this.heartbeatSetInterval);
-      this.heartbeatSetInterval = null;
     }
   }
 
@@ -815,7 +815,7 @@ export default class ChargingStation {
     if (Utils.isUndefined(options)) {
       options = {} as WebSocket.ClientOptions;
     }
-    if (Utils.isUndefined(options.handshakeTimeout)) {
+    if (Utils.isUndefined(options?.handshakeTimeout)) {
       options.handshakeTimeout = this.getConnectionTimeout() * 1000;
     }
     if (this.isWebSocketOpen() && forceCloseOpened) {
@@ -864,7 +864,8 @@ export default class ChargingStation {
             this.automaticTransactionGeneration = new AutomaticTransactionGenerator(this);
           }
           if (this.automaticTransactionGeneration.timeToStop) {
-            await this.automaticTransactionGeneration.start();
+            // The ATG might sleep
+            void this.automaticTransactionGeneration.start();
           }
         }
         // FIXME?: restart heartbeat and WebSocket ping when their interval values have changed
@@ -874,11 +875,11 @@ export default class ChargingStation {
     });
   }
 
-  private getReconnectExponentialDelay(): boolean {
+  private getReconnectExponentialDelay(): boolean | undefined {
     return !Utils.isUndefined(this.stationInfo.reconnectExponentialDelay) ? this.stationInfo.reconnectExponentialDelay : false;
   }
 
-  private async reconnect(error): Promise<void> {
+  private async reconnect(error: any): Promise<void> {
     // Stop heartbeat
     this.stopHeartbeat();
     // Stop the ATG if needed
@@ -903,8 +904,8 @@ export default class ChargingStation {
 
   private initTransactionOnConnector(connectorId: number): void {
     this.getConnector(connectorId).transactionStarted = false;
-    this.getConnector(connectorId).transactionId = null;
-    this.getConnector(connectorId).idTag = null;
+    delete this.getConnector(connectorId).transactionId;
+    delete this.getConnector(connectorId).idTag;
     this.getConnector(connectorId).lastEnergyActiveImportRegisterValue = -1;
   }
 }
index 84cb023b7334297d751f3bf51f7515223eac2575..5977b8e0eae322cdb32b1493d6e4719faf4357ca 100644 (file)
@@ -22,7 +22,7 @@ if (Utils.workerPoolInUse()) {
  * Listen messages send by the main thread
  */
 function addMessageListener(): void {
-  parentPort.on('message', (message) => {
+  parentPort?.on('message', (message) => {
     if (message.id === WorkerEvents.START_WORKER_ELEMENT) {
       startChargingStation(message.workerData);
     }
index 6b8443520490718cd4075e5fcb420b9f2f2324ee..f230b3bcbad1b30ef21aeec40e866ee20ea33899 100644 (file)
@@ -190,7 +190,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
       let clearedCP = false;
       for (const connector in this.chargingStation.connectors) {
         if (!Utils.isEmptyArray(this.chargingStation.getConnector(Utils.convertToInt(connector)).chargingProfiles)) {
-          this.chargingStation.getConnector(Utils.convertToInt(connector)).chargingProfiles.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
+          this.chargingStation.getConnector(Utils.convertToInt(connector)).chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
             let clearCurrentCP = false;
             if (chargingProfile.chargingProfileId === commandPayload.id) {
               clearCurrentCP = true;
@@ -271,7 +271,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag);
           return Constants.OCPP_RESPONSE_ACCEPTED;
         }
-        logger.error(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag);
+        logger.warn(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag);
         return Constants.OCPP_RESPONSE_REJECTED;
       }
       await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorID, OCPP16ChargePointStatus.PREPARING);
@@ -287,7 +287,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
       logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag);
       return Constants.OCPP_RESPONSE_ACCEPTED;
     }
-    logger.error(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on unavailable connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag);
+    logger.warn(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on unavailable connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag);
     return Constants.OCPP_RESPONSE_REJECTED;
   }
 
index e9f7ee6dbb6dfe3df4a74542f83605cb967cbe6e..8e5c3ffacdc0c38716142e7bc1ca309dd5ec7000 100644 (file)
@@ -4,6 +4,7 @@ import { MeterValue, MeterValueLocation, MeterValuePhase, MeterValueUnit, MeterV
 
 import { ACElectricUtils } from '../../../utils/ElectricUtils';
 import Constants from '../../../utils/Constants';
+import { CurrentOutType } from '../../../types/ChargingStationTemplate';
 import MeasurandValues from '../../../types/MeasurandValues';
 import { MessageType } from '../../../types/ocpp/MessageType';
 import { OCPP16BootNotificationResponse } from '../../../types/ocpp/1.6/Responses';
@@ -12,7 +13,6 @@ import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStat
 import { OCPP16StandardParametersKey } from '../../../types/ocpp/1.6/Configuration';
 import OCPPError from '../../OcppError';
 import OCPPRequestService from '../OCPPRequestService';
-import { PowerOutType } from '../../../types/ChargingStationTemplate';
 import Utils from '../../../utils/Utils';
 import logger from '../../../utils/Logger';
 
@@ -62,7 +62,7 @@ export default class OCPP16RequestService extends OCPPRequestService {
   public async sendAuthorize(idTag?: string): Promise<OCPP16AuthorizeResponse> {
     try {
       const payload: AuthorizeRequest = {
-        ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_TAGID },
+        ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_IDTAG },
       };
       return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.AUTHORIZE) as OCPP16AuthorizeResponse;
     } catch (error) {
@@ -74,7 +74,7 @@ export default class OCPP16RequestService extends OCPPRequestService {
     try {
       const payload: StartTransactionRequest = {
         connectorId,
-        ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_TAGID },
+        ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_IDTAG },
         meterStart: 0,
         timestamp: new Date().toISOString(),
       };
@@ -161,12 +161,12 @@ export default class OCPP16RequestService extends OCPPRequestService {
             logger.error(errMsg);
             throw Error(errMsg);
           }
-          const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getPowerOutType()} powerOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`;
+          const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getCurrentOutType()} currentOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`;
           const powerMeasurandValues = {} as MeasurandValues;
           const maxPower = Math.round(self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider);
           const maxPowerPerPhase = Math.round((self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider) / self.chargingStation.getNumberOfPhases());
-          switch (self.chargingStation.getPowerOutType()) {
-            case PowerOutType.AC:
+          switch (self.chargingStation.getCurrentOutType()) {
+            case CurrentOutType.AC:
               if (Utils.isUndefined(meterValuesTemplate[index].value)) {
                 powerMeasurandValues.L1 = Utils.getRandomFloatRounded(maxPowerPerPhase);
                 powerMeasurandValues.L2 = 0;
@@ -178,7 +178,7 @@ export default class OCPP16RequestService extends OCPPRequestService {
                 powerMeasurandValues.allPhases = Utils.roundTo(powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3, 2);
               }
               break;
-            case PowerOutType.DC:
+            case CurrentOutType.DC:
               if (Utils.isUndefined(meterValuesTemplate[index].value)) {
                 powerMeasurandValues.allPhases = Utils.getRandomFloatRounded(maxPower);
               }
@@ -221,11 +221,11 @@ export default class OCPP16RequestService extends OCPPRequestService {
             logger.error(errMsg);
             throw Error(errMsg);
           }
-          const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getPowerOutType()} powerOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`;
+          const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getCurrentOutType()} currentOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`;
           const currentMeasurandValues: MeasurandValues = {} as MeasurandValues;
           let maxAmperage: number;
-          switch (self.chargingStation.getPowerOutType()) {
-            case PowerOutType.AC:
+          switch (self.chargingStation.getCurrentOutType()) {
+            case CurrentOutType.AC:
               maxAmperage = ACElectricUtils.amperagePerPhaseFromPower(self.chargingStation.getNumberOfPhases(), self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider, self.chargingStation.getVoltageOut());
               if (Utils.isUndefined(meterValuesTemplate[index].value)) {
                 currentMeasurandValues.L1 = Utils.getRandomFloatRounded(maxAmperage);
@@ -238,7 +238,7 @@ export default class OCPP16RequestService extends OCPPRequestService {
                 currentMeasurandValues.allPhases = Utils.roundTo((currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) / self.chargingStation.getNumberOfPhases(), 2);
               }
               break;
-            case PowerOutType.DC:
+            case CurrentOutType.DC:
               maxAmperage = ACElectricUtils.amperageTotalFromPower(self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider, self.chargingStation.getVoltageOut());
               if (Utils.isUndefined(meterValuesTemplate[index].value)) {
                 currentMeasurandValues.allPhases = Utils.getRandomFloatRounded(maxAmperage);
@@ -314,9 +314,9 @@ export default class OCPP16RequestService extends OCPPRequestService {
         transactionId,
         meterValue,
       };
-      await self.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.METERVALUES);
+      await self.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.METER_VALUES);
     } catch (error) {
-      self.handleRequestError(OCPP16RequestCommand.METERVALUES, error);
+      self.handleRequestError(OCPP16RequestCommand.METER_VALUES, error);
     }
   }
 
index cf1c9212d87ee4ff26be6888edd26ac378fb37e1..e9d2d2e9dc18477b70769f9d79682ea8b51f4700 100644 (file)
@@ -21,13 +21,13 @@ export default class OCPP16ResponseService extends OCPPResponseService {
 
   private handleResponseBootNotification(payload: OCPP16BootNotificationResponse, requestPayload: OCPP16BootNotificationRequest): void {
     if (payload.status === OCPP16RegistrationStatus.ACCEPTED) {
-      this.chargingStation.heartbeatSetInterval ? this.chargingStation.restartHeartbeat() : this.chargingStation.startHeartbeat();
       this.chargingStation.addConfigurationKey(OCPP16StandardParametersKey.HeartBeatInterval, payload.interval.toString());
       this.chargingStation.addConfigurationKey(OCPP16StandardParametersKey.HeartbeatInterval, payload.interval.toString(), false, false);
+      this.chargingStation.heartbeatSetInterval ? this.chargingStation.restartHeartbeat() : this.chargingStation.startHeartbeat();
     } else if (payload.status === OCPP16RegistrationStatus.PENDING) {
       logger.info(this.chargingStation.logPrefix() + ' Charging station in pending state on the central server');
     } else {
-      logger.info(this.chargingStation.logPrefix() + ' Charging station rejected by the central server');
+      logger.warn(this.chargingStation.logPrefix() + ' Charging station rejected by the central server');
     }
   }
 
@@ -50,7 +50,7 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       return;
     }
 
-    if (payload?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
+    if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
       this.chargingStation.getConnector(connectorId).transactionStarted = true;
       this.chargingStation.getConnector(connectorId).transactionId = payload.transactionId;
       this.chargingStation.getConnector(connectorId).idTag = requestPayload.idTag;
@@ -64,7 +64,7 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       const configuredMeterValueSampleInterval = this.chargingStation.getConfigurationKey(OCPP16StandardParametersKey.MeterValueSampleInterval);
       this.chargingStation.startMeterValues(connectorId, configuredMeterValueSampleInterval ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000 : 60000);
     } else {
-      logger.error(this.chargingStation.logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload?.idTagInfo?.status + ', idTag ' + requestPayload.idTag);
+      logger.warn(this.chargingStation.logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload?.idTagInfo?.status + ', idTag ' + requestPayload.idTag);
       this.chargingStation.resetTransactionOnConnector(connectorId);
       await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.AVAILABLE);
       this.chargingStation.getConnector(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
@@ -97,7 +97,7 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       logger.info(this.chargingStation.logPrefix() + ' Transaction ' + requestPayload.transactionId.toString() + ' STOPPED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString());
       this.chargingStation.resetTransactionOnConnector(transactionConnectorId);
     } else {
-      logger.error(this.chargingStation.logPrefix() + ' Stopping transaction id ' + requestPayload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo?.status);
+      logger.warn(this.chargingStation.logPrefix() + ' Stopping transaction id ' + requestPayload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo?.status);
     }
   }
 
index 5615eb7705411c04f3054e07b2e1ed4daa0628e8..70742ea8cb472e304df44beb7d95964bdc597fba 100644 (file)
@@ -1,5 +1,5 @@
 import { AuthorizeResponse, StartTransactionResponse, StopTransactionReason, StopTransactionResponse } from '../../types/ocpp/Transaction';
-import { IncomingRequestCommand, Request, RequestCommand } from '../../types/ocpp/Requests';
+import { IncomingRequestCommand, RequestCommand } from '../../types/ocpp/Requests';
 
 import { BootNotificationResponse } from '../../types/ocpp/Responses';
 import { ChargePointErrorCode } from '../../types/ocpp/ChargePointErrorCode';
@@ -21,8 +21,7 @@ export default abstract class OCPPRequestService {
     this.ocppResponseService = ocppResponseService;
   }
 
-  public async sendMessage(messageId: string, commandParams: any, messageType: MessageType = MessageType.CALL_RESULT_MESSAGE,
-      commandName: RequestCommand | IncomingRequestCommand): Promise<any> {
+  public async sendMessage(messageId: string, commandParams: any, messageType: MessageType, commandName: RequestCommand | IncomingRequestCommand): Promise<any> {
     // eslint-disable-next-line @typescript-eslint/no-this-alias
     const self = this;
     // Send a message through wsConnection
@@ -33,7 +32,7 @@ export default abstract class OCPPRequestService {
         // Request
         case MessageType.CALL_MESSAGE:
           // Build request
-          this.chargingStation.requests[messageId] = [responseCallback, rejectCallback, commandParams] as Request;
+          this.chargingStation.requests[messageId] = [responseCallback, rejectCallback, commandParams as Record<string, unknown>];
           messageToSend = JSON.stringify([messageType, messageId, commandName, commandParams]);
           break;
         // Response
@@ -50,7 +49,7 @@ export default abstract class OCPPRequestService {
       // Check if wsConnection opened and charging station registered
       if (this.chargingStation.isWebSocketOpen() && (this.chargingStation.isRegistered() || commandName === RequestCommand.BOOT_NOTIFICATION)) {
         if (this.chargingStation.getEnableStatistics()) {
-          this.chargingStation.statistics.addMessage(commandName, messageType);
+          this.chargingStation.performanceStatistics.addMessage(commandName, messageType);
         }
         // Yes: Send Message
         this.chargingStation.wsConnection.send(messageToSend);
@@ -77,7 +76,7 @@ export default abstract class OCPPRequestService {
        */
       async function responseCallback(payload: Record<string, unknown> | string, requestPayload: Record<string, unknown>): Promise<void> {
         if (self.chargingStation.getEnableStatistics()) {
-          self.chargingStation.statistics.addMessage(commandName, messageType);
+          self.chargingStation.performanceStatistics.addMessage(commandName, MessageType.CALL_RESULT_MESSAGE);
         }
         // Send the response
         await self.ocppResponseService.handleResponse(commandName as RequestCommand, payload, requestPayload);
@@ -91,7 +90,7 @@ export default abstract class OCPPRequestService {
        */
       function rejectCallback(error: OCPPError): void {
         if (self.chargingStation.getEnableStatistics()) {
-          self.chargingStation.statistics.addMessage(commandName, messageType);
+          self.chargingStation.performanceStatistics.addMessage(commandName, MessageType.CALL_ERROR_MESSAGE);
         }
         logger.debug(`${self.chargingStation.logPrefix()} Error: %j occurred when calling command %s with parameters: %j`, error, commandName, commandParams);
         // Build Exception
index b3b05b669099b40167f8a4bfbe0a0a7d8eafdee5..44aea77fcaadd3aa67dc256c0c8c32195dc45fc2 100644 (file)
@@ -3,12 +3,12 @@ import Connectors from './Connectors';
 import { OCPPProtocol } from './ocpp/OCPPProtocol';
 import { OCPPVersion } from './ocpp/OCPPVersion';
 
-export enum PowerOutType {
+export enum CurrentOutType {
   AC = 'AC',
   DC = 'DC',
 }
 
-export enum PowerUnit {
+export enum PowerUnits {
   WATT = 'W',
   KILO_WATT = 'kW',
 }
@@ -38,15 +38,15 @@ export default interface ChargingStationTemplate {
   authorizationFile?: string;
   baseName: string;
   nameSuffix?: string;
-  fixedName?: string;
+  fixedName?: boolean;
   chargePointModel: string;
   chargePointVendor: string;
   chargeBoxSerialNumberPrefix?: string;
   firmwareVersion?: string;
   power: number | number[];
   powerSharedByConnectors?: boolean;
-  powerUnit: PowerUnit;
-  powerOutType?: PowerOutType;
+  powerUnit: PowerUnits;
+  currentOutType?: CurrentOutType;
   numberOfPhases?: number;
   numberOfConnectors?: number | number[];
   useConnectorId0?: boolean;
index 84f2bdcae5634204f22e483f6ff4e1ffa9260a38..2b84a5e4abca4e368deaf332ce31e18a85db059c 100644 (file)
@@ -1,4 +1,4 @@
-import CircularArray from '../utils/CircularArray';
+import { CircularArray } from '../utils/CircularArray';
 import { EntryType } from 'perf_hooks';
 
 export interface PerfEntry {
@@ -20,6 +20,7 @@ export interface CommandStatisticsData {
   totalTimeMeasurement: number;
   avgTimeMeasurement: number;
   medTimeMeasurement: number;
+  stdDevTimeMeasurement: number;
 }
 
 export default interface CommandStatistics {
index 125ecef636d693afc840fd16b35abde81308a0ec..6d67a06e741207fb670fa712e716e9aa662a33d7 100644 (file)
@@ -1,3 +1,4 @@
+import type { WorkerChoiceStrategy } from 'poolifier';
 import { WorkerProcessType } from './Worker';
 
 export interface StationTemplateURL {
@@ -13,8 +14,10 @@ export default interface ConfigurationData {
   autoReconnectMaxRetries?: number;
   distributeStationsToTenantsEqually?: boolean;
   workerProcess?: WorkerProcessType;
+  workerStartDelay?: number;
   workerPoolMinSize?: number;
   workerPoolMaxSize?: number;
+  workerPoolStrategy?: WorkerChoiceStrategy;
   chargingStationsPerWorker?: number;
   logFormat?: string;
   logLevel?: string;
index bc2972684c0cb2677f34176ffbd11b119392d423..c1f6f0c89ae3c197d26eb1a37c6fa3edb2c1c328 100644 (file)
@@ -1,3 +1,4 @@
+import { PoolOptions } from 'poolifier';
 import { Worker } from 'worker_threads';
 
 export enum WorkerProcessType {
@@ -7,12 +8,15 @@ export enum WorkerProcessType {
 }
 
 export interface WorkerOptions {
+  startDelay?: number;
   poolMaxSize?: number;
   poolMinSize?: number;
   elementsPerWorker?: number;
+  poolOptions?: PoolOptions<Worker>;
 }
 
-export interface WorkerData { }
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface WorkerData {}
 
 export interface StationWorkerData extends WorkerData {
   index: number;
index 8af407c0ac3789fceb6ca52fb54c3cbec133398f..9ed48049a52cb70915cf8c1955f914d42a236453 100644 (file)
@@ -12,7 +12,7 @@ export enum OCPP16RequestCommand {
   AUTHORIZE = 'Authorize',
   START_TRANSACTION = 'StartTransaction',
   STOP_TRANSACTION = 'StopTransaction',
-  METERVALUES = 'MeterValues'
+  METER_VALUES = 'MeterValues'
 }
 
 export enum OCPP16IncomingRequestCommand {
index d4388efe7c9c957aa3a1a4fe82374e608cea6881..aeb6828c7c97cd1e9e1bcff8ebcf3c480a45f5de 100644 (file)
@@ -27,6 +27,6 @@ export const IncomingRequestCommand = {
   ...OCPP16IncomingRequestCommand
 };
 
-export type Request = [(payload?: Record<string, unknown>, requestPayload?: Record<string, unknown>) => void, (error?: OCPPError) => void, Record<string, unknown>];
+export type Request = [(payload: Record<string, unknown> | string, requestPayload: Record<string, unknown>) => void, (error: OCPPError) => void, Record<string, unknown>];
 
 export type IncomingRequest = [MessageType, string, IncomingRequestCommand, Record<string, unknown>, Record<string, unknown>];
index 535fb00e5cd34c811d03e96125e608d4ae6693d3..93dacdb0ee8d421f592ff6b05e31ef1b23b9acc4 100644 (file)
@@ -1,36 +1,85 @@
+export const DEFAULT_CIRCULAR_ARRAY_SIZE = 2000;
 
-export default class CircularArray<T> extends Array<T> {
-  size: number;
-  private readonly maximumCircularArraySize = 2000;
+/** Array with a maximum length shifting items when full. */
+export class CircularArray<T> extends Array<T> {
+  public size: number;
 
-  constructor(size?: number) {
+  constructor(size: number = DEFAULT_CIRCULAR_ARRAY_SIZE, ...items: T[]) {
     super();
-    this.size = size && size <= this.maximumCircularArraySize ? size : this.maximumCircularArraySize;
+    this.checkSize(size);
+    this.size = size;
+    if (arguments.length > 1) {
+      this.push(...items);
+    }
+  }
+
+  public push(...items: T[]): number {
+    const length = super.push(...items);
+    if (length > this.size) {
+      super.splice(0, length - this.size);
+    }
+    return this.length;
+  }
+
+  public unshift(...items: T[]): number {
+    const length = super.unshift(...items);
+    if (length > this.size) {
+      super.splice(this.size, items.length);
+    }
+    return this.length;
   }
 
-  push(...items: T[]): number {
-    if (this.length + items.length > this.size) {
-      super.splice(0, (this.length + items.length) - this.size);
+  public concat(...items: (T | ConcatArray<T>)[]): CircularArray<T> {
+    const concatenatedCircularArray = super.concat(
+      items as T[]
+    ) as CircularArray<T>;
+    concatenatedCircularArray.size = this.size;
+    if (concatenatedCircularArray.length > concatenatedCircularArray.size) {
+      concatenatedCircularArray.splice(
+        0,
+        concatenatedCircularArray.length - concatenatedCircularArray.size
+      );
     }
-    return super.push(...items);
+    return concatenatedCircularArray;
   }
 
-  unshift(...items: T[]): number {
-    if (this.length + items.length > this.size) {
-      super.splice(this.size - items.length, (this.length + items.length) - this.size);
+  public splice(start: number, deleteCount?: number, ...items: T[]): T[] {
+    let itemsRemoved: T[];
+    if (arguments.length >= 3 && typeof deleteCount !== 'undefined') {
+      itemsRemoved = super.splice(start, deleteCount);
+      // FIXME: that makes the items insert not in place
+      this.push(...items);
+    } else if (arguments.length === 2) {
+      itemsRemoved = super.splice(start, deleteCount);
+    } else {
+      itemsRemoved = super.splice(start);
     }
-    return super.unshift(...items);
+    return itemsRemoved;
   }
 
-  concat(...items: (T | ConcatArray<T>)[]): T[] {
-    if (this.length + items.length > this.size) {
-      super.splice(0, (this.length + items.length) - this.size);
+  public resize(size: number): void {
+    this.checkSize(size);
+    if (size === 0) {
+      this.length = 0;
+    } else if (size < this.size) {
+      for (let i = size; i < this.size; i++) {
+        super.pop();
+      }
     }
-    return super.concat(items as T[]);
+    this.size = size;
+  }
+
+  public empty(): boolean {
+    return this.length === 0;
   }
 
-  splice(start: number, deleteCount?: number, ...items: T[]): T[] {
-    this.push(...items);
-    return super.splice(start, deleteCount);
+  public full(): boolean {
+    return this.length === this.size;
+  }
+
+  private checkSize(size: number) {
+    if (size < 0) {
+      throw new RangeError('Invalid circular array size');
+    }
   }
 }
index 552fab21dc21bb764b179a7ca49078c2ae4214f4..0926115ce41a0f016b75c799114d8a4553806695 100644 (file)
@@ -1,5 +1,7 @@
 import ConfigurationData, { StationTemplateURL } from '../types/ConfigurationData';
 
+import Constants from './Constants';
+import type { WorkerChoiceStrategy } from 'poolifier';
 import { WorkerProcessType } from '../types/Worker';
 import fs from 'fs';
 import path from 'path';
@@ -7,7 +9,7 @@ import path from 'path';
 export default class Configuration {
   private static configurationFilePath = path.join(path.resolve(__dirname, '../'), 'assets', 'config.json');
   private static configurationFileWatcher: fs.FSWatcher;
-  private static configuration: ConfigurationData;
+  private static configuration: ConfigurationData | null = null;
   private static configurationChangeCallback: () => Promise<void>;
 
   static setConfigurationChangeCallback(cb: () => Promise<void>): void {
@@ -51,6 +53,10 @@ export default class Configuration {
     return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerProcess') ? Configuration.getConfig().workerProcess : WorkerProcessType.WORKER_SET;
   }
 
+  static getWorkerStartDelay(): number {
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerStartDelay') ? Configuration.getConfig().workerStartDelay : Constants.WORKER_START_DELAY;
+  }
+
   static getWorkerPoolMinSize(): number {
     return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerPoolMinSize') ? Configuration.getConfig().workerPoolMinSize : 4;
   }
@@ -60,6 +66,10 @@ export default class Configuration {
     return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerPoolMaxSize') ? Configuration.getConfig().workerPoolMaxSize : 16;
   }
 
+  static getWorkerPoolStrategy(): WorkerChoiceStrategy {
+    return Configuration.getConfig().workerPoolStrategy;
+  }
+
   static getChargingStationsPerWorker(): number {
     return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'chargingStationsPerWorker') ? Configuration.getConfig().chargingStationsPerWorker : 1;
   }
@@ -133,7 +143,7 @@ export default class Configuration {
   }
 
   private static objectHasOwnProperty(object: any, property: string): boolean {
-    return Object.prototype.hasOwnProperty.call(object, property) as boolean;
+    return Object.prototype.hasOwnProperty.call(object, property);
   }
 
   private static isUndefined(obj: any): boolean {
index 1959ed935340ebf7424285fc682a5213ffa03d05..8b1df1ca31983bbd400ec0a0c039be124de111d4 100644 (file)
@@ -29,8 +29,8 @@ export default class Constants {
   static readonly CHARGING_STATION_ATG_WAIT_TIME = 2000; // Ms
   static readonly CHARGING_STATION_ATG_INITIALIZATION_TIME = 1000; // Ms
 
-  static readonly TRANSACTION_DEFAULT_TAGID = '00000000';
+  static readonly TRANSACTION_DEFAULT_IDTAG = '00000000';
 
-  static readonly START_WORKER_DELAY = 500;
+  static readonly WORKER_START_DELAY = 500;
   static readonly WORKER_POOL_MAX_INACTIVE_TIME = 60000;
 }
similarity index 82%
rename from src/utils/Statistics.ts
rename to src/utils/PerformanceStatistics.ts
index d194451a031e5b2a3078f2107f8211ffa8f76de9..bcd0b71f69888318b1e5dfd35a2e2fc67757af2e 100644 (file)
@@ -1,14 +1,14 @@
+import { CircularArray, DEFAULT_CIRCULAR_ARRAY_SIZE } from './CircularArray';
 import CommandStatistics, { CommandStatisticsData, PerfEntry } from '../types/CommandStatistics';
 import { IncomingRequestCommand, RequestCommand } from '../types/ocpp/Requests';
 
-import CircularArray from './CircularArray';
 import Configuration from './Configuration';
 import { MessageType } from '../types/ocpp/MessageType';
 import { PerformanceEntry } from 'perf_hooks';
 import Utils from './Utils';
 import logger from './Logger';
 
-export default class Statistics {
+export default class PerformanceStatistics {
   private objId: string;
   private commandsStatistics: CommandStatistics;
 
@@ -52,7 +52,7 @@ export default class Statistics {
         }
         break;
       default:
-        logger.error(`${this.logPrefix()} Wrong message type ${messageType}`);
+        logger.error(`${this.logPrefix()} wrong message type ${messageType}`);
         break;
     }
   }
@@ -64,7 +64,7 @@ export default class Statistics {
     perfEntry.entryType = entry.entryType;
     perfEntry.startTime = entry.startTime;
     perfEntry.duration = entry.duration;
-    logger.info(`${this.logPrefix()} object ${className} method(s) performance entry: %j`, perfEntry);
+    logger.info(`${this.logPrefix()} ${className} method(s) entry: %j`, perfEntry);
   }
 
   public start(): void {
@@ -96,15 +96,29 @@ export default class Statistics {
     return (sortedDataSet[(middleIndex - 1)] + sortedDataSet[middleIndex]) / 2;
   }
 
+  private stdDeviation(dataSet: number[]): number {
+    let totalDataSet = 0;
+    for (const data of dataSet) {
+      totalDataSet += data;
+    }
+    const dataSetMean = totalDataSet / dataSet.length;
+    let totalGeometricDeviation = 0;
+    for (const data of dataSet) {
+      const deviation = data - dataSetMean;
+      totalGeometricDeviation += deviation * deviation;
+    }
+    return Math.sqrt(totalGeometricDeviation / dataSet.length);
+  }
+
   private addPerformanceTimer(command: RequestCommand | IncomingRequestCommand, duration: number): void {
     // Map to proper command name
-    const MAPCOMMAND = {
-      sendMeterValues: 'MeterValues',
-      startTransaction: 'StartTransaction',
-      stopTransaction: 'StopTransaction',
+    const MAP_COMMAND = {
+      sendMeterValues: RequestCommand.METER_VALUES,
+      startTransaction: RequestCommand.START_TRANSACTION,
+      stopTransaction: RequestCommand.STOP_TRANSACTION,
     };
-    if (MAPCOMMAND[command]) {
-      command = MAPCOMMAND[command] as RequestCommand | IncomingRequestCommand;
+    if (MAP_COMMAND[command]) {
+      command = MAP_COMMAND[command] as RequestCommand | IncomingRequestCommand;
     }
     // Initialize command statistics
     if (!this.commandsStatistics.commandsStatisticsData[command]) {
@@ -117,11 +131,12 @@ export default class Statistics {
     this.commandsStatistics.commandsStatisticsData[command].maxTimeMeasurement = this.commandsStatistics.commandsStatisticsData[command].maxTimeMeasurement ? (this.commandsStatistics.commandsStatisticsData[command].maxTimeMeasurement < duration ? duration : this.commandsStatistics.commandsStatisticsData[command].maxTimeMeasurement) : duration;
     this.commandsStatistics.commandsStatisticsData[command].totalTimeMeasurement = this.commandsStatistics.commandsStatisticsData[command].totalTimeMeasurement ? this.commandsStatistics.commandsStatisticsData[command].totalTimeMeasurement + duration : duration;
     this.commandsStatistics.commandsStatisticsData[command].avgTimeMeasurement = this.commandsStatistics.commandsStatisticsData[command].totalTimeMeasurement / this.commandsStatistics.commandsStatisticsData[command].countTimeMeasurement;
-    Array.isArray(this.commandsStatistics.commandsStatisticsData[command].timeMeasurementSeries) ? this.commandsStatistics.commandsStatisticsData[command].timeMeasurementSeries.push(duration) : this.commandsStatistics.commandsStatisticsData[command].timeMeasurementSeries = [duration] as CircularArray<number>;
+    Array.isArray(this.commandsStatistics.commandsStatisticsData[command].timeMeasurementSeries) ? this.commandsStatistics.commandsStatisticsData[command].timeMeasurementSeries.push(duration) : this.commandsStatistics.commandsStatisticsData[command].timeMeasurementSeries = new CircularArray<number>(DEFAULT_CIRCULAR_ARRAY_SIZE, duration);
     this.commandsStatistics.commandsStatisticsData[command].medTimeMeasurement = this.median(this.commandsStatistics.commandsStatisticsData[command].timeMeasurementSeries);
+    this.commandsStatistics.commandsStatisticsData[command].stdDevTimeMeasurement = this.stdDeviation(this.commandsStatistics.commandsStatisticsData[command].timeMeasurementSeries);
   }
 
   private logPrefix(): string {
-    return Utils.logPrefix(` ${this.objId} Statistics:`);
+    return Utils.logPrefix(` ${this.objId} | Performance statistics`);
   }
 }
index 25ac7634e28f3c4584d4fecda288be0de2f6387d..6d37271ff6382f06c18711aed2e0852ddae61f0c 100644 (file)
@@ -36,7 +36,7 @@ export default class Utils {
     }
   }
 
-  static convertToDate(value): Date {
+  static convertToDate(value: any): Date {
     // Check
     if (!value) {
       return value;
@@ -48,7 +48,7 @@ export default class Utils {
     return value;
   }
 
-  static convertToInt(value): number {
+  static convertToInt(value: any): number {
     let changedValue = value;
     if (!value) {
       return 0;
@@ -64,7 +64,7 @@ export default class Utils {
     return changedValue;
   }
 
-  static convertToFloat(value): number {
+  static convertToFloat(value: any): number {
     let changedValue = value;
     if (!value) {
       return 0;
@@ -77,7 +77,7 @@ export default class Utils {
     return changedValue;
   }
 
-  static convertToBoolean(value): boolean {
+  static convertToBoolean(value: any): boolean {
     let result = false;
     // Check boolean
     if (value) {
@@ -130,14 +130,14 @@ export default class Utils {
     return JSON.parse(JSON.stringify(object)) as T;
   }
 
-  static isIterable(obj): boolean {
+  static isIterable<T>(obj: T): boolean {
     if (obj) {
       return typeof obj[Symbol.iterator] === 'function';
     }
     return false;
   }
 
-  static isEmptyJSon(document): boolean {
+  static isEmptyJSon(document: any): boolean {
     // Empty?
     if (!document) {
       return true;
@@ -150,15 +150,15 @@ export default class Utils {
     return Object.keys(document).length === 0;
   }
 
-  static isString(value): boolean {
+  static isString(value: any): boolean {
     return typeof value === 'string';
   }
 
-  static isUndefined(value): boolean {
+  static isUndefined(value: any): boolean {
     return typeof value === 'undefined';
   }
 
-  static isNullOrUndefined(value): boolean {
+  static isNullOrUndefined(value: any): boolean {
     // eslint-disable-next-line no-eq-null, eqeqeq
     if (value == null) {
       return true;
@@ -166,7 +166,7 @@ export default class Utils {
     return false;
   }
 
-  static isEmptyArray(object): boolean {
+  static isEmptyArray(object: any): boolean {
     if (!object) {
       return true;
     }
@@ -176,7 +176,7 @@ export default class Utils {
     return true;
   }
 
-  static isEmptyObject(obj): boolean {
+  static isEmptyObject(obj: any): boolean {
     return !Object.keys(obj).length;
   }
 
index 9f16af737457cf5daa522a1d25859514a6b6b3b1..715778161af13b59bed90aa2805b0120451c64b8 100644 (file)
@@ -1,17 +1,21 @@
+import Constants from '../utils/Constants';
 import { WorkerData } from '../types/Worker';
 
 export default abstract class WorkerAbstract {
-  protected workerScript: string;
+  protected readonly workerScript: string;
+  protected readonly workerStartDelay: number;
   public abstract size: number;
-  public abstract maxElementsPerWorker: number;
+  public abstract maxElementsPerWorker: number | null;
 
   /**
    * `WorkerAbstract` constructor.
    *
    * @param {string} workerScript
+   * @param {number} workerStartDelay
    */
-  constructor(workerScript: string) {
+  constructor(workerScript: string, workerStartDelay: number = Constants.WORKER_START_DELAY) {
     this.workerScript = workerScript;
+    this.workerStartDelay = workerStartDelay;
   }
 
   public abstract start(): Promise<void>;
index a9aa56f09765912a3a4193bb8acc299654d1d3a2..9141c2f0b2f05ae3beb4c597731e4e256f326187 100644 (file)
@@ -1,6 +1,5 @@
 import { DynamicThreadPool, PoolOptions } from 'poolifier';
 
-import Constants from '../utils/Constants';
 import Utils from '../utils/Utils';
 import { Worker } from 'worker_threads';
 import WorkerAbstract from './WorkerAbstract';
@@ -15,17 +14,19 @@ export default class WorkerDynamicPool<T> extends WorkerAbstract {
    * @param {string} workerScript
    * @param {number} min
    * @param {number} max
+   * @param {number} workerStartDelay
+   * @param {PoolOptions} opts
    */
-  constructor(workerScript: string, min: number, max: number,) {
-    super(workerScript);
-    this.pool = DynamicPool.getInstance(min, max, this.workerScript);
+  constructor(workerScript: string, min: number, max: number, workerStartDelay?: number, opts?: PoolOptions<Worker>) {
+    super(workerScript, workerStartDelay);
+    this.pool = DynamicPool.getInstance(min, max, this.workerScript, opts);
   }
 
   get size(): number {
     return this.pool.workers.length;
   }
 
-  get maxElementsPerWorker(): number {
+  get maxElementsPerWorker(): number | null {
     return null;
   }
 
@@ -49,14 +50,14 @@ export default class WorkerDynamicPool<T> extends WorkerAbstract {
 
   /**
    *
-   * @param elementData
+   * @param {T} elementData
    * @returns {Promise<void>}
    * @public
    */
   public async addElement(elementData: T): Promise<void> {
     await this.pool.execute(elementData);
     // Start worker sequentially to optimize memory at startup
-    await Utils.sleep(Constants.START_WORKER_DELAY);
+    await Utils.sleep(this.workerStartDelay);
   }
 }
 
@@ -67,17 +68,14 @@ class DynamicPool extends DynamicThreadPool<WorkerData> {
     super(min, max, workerScript, opts);
   }
 
-  public static getInstance(min: number, max: number, workerScript: string): DynamicPool {
+  public static getInstance(min: number, max: number, workerScript: string, opts?: PoolOptions<Worker>): DynamicPool {
     if (!DynamicPool.instance) {
-      DynamicPool.instance = new DynamicPool(min, max, workerScript,
-        {
-          exitHandler: (code) => {
-            if (code !== 0) {
-              console.error(`Worker stopped with exit code ${code}`);
-            }
-          }
+      opts.exitHandler = opts?.exitHandler ?? ((code) => {
+        if (code !== 0) {
+          console.error(`Worker stopped with exit code ${code}`);
         }
-      );
+      });
+      DynamicPool.instance = new DynamicPool(min, max, workerScript, opts);
     }
     return DynamicPool.instance;
   }
index 41fa1d89715444ca5cd69b07f6684789f63b2ecc..f4307be6bde3b159d5e35ccbf6159061046456bf 100644 (file)
@@ -1,6 +1,6 @@
 import { WorkerOptions, WorkerProcessType } from '../types/Worker';
 
-import Utils from '../utils/Utils';
+import Constants from '../utils/Constants';
 import WorkerAbstract from './WorkerAbstract';
 import WorkerDynamicPool from './WorkerDynamicPool';
 import WorkerSet from './WorkerSet';
@@ -8,32 +8,23 @@ import WorkerStaticPool from './WorkerStaticPool';
 import { isMainThread } from 'worker_threads';
 
 export default class WorkerFactory {
-  public static getWorkerImplementation<T>(workerScript: string, workerProcessType: WorkerProcessType, options?: WorkerOptions): WorkerAbstract {
+  public static getWorkerImplementation<T>(workerScript: string, workerProcessType: WorkerProcessType, options?: WorkerOptions): WorkerAbstract | null {
     if (!isMainThread) {
       throw new Error('Trying to get a worker implementation outside the main thread');
     }
-    if (Utils.isUndefined(options)) {
-      options = {} as WorkerOptions;
-    }
+    options = options ?? {} as WorkerOptions;
+    options.startDelay = options.startDelay ?? Constants.WORKER_START_DELAY;
     switch (workerProcessType) {
       case WorkerProcessType.WORKER_SET:
-        if (Utils.isUndefined(options.elementsPerWorker)) {
-          options.elementsPerWorker = 1;
-        }
-        return new WorkerSet<T>(workerScript, options.elementsPerWorker);
+        options.elementsPerWorker = options.elementsPerWorker ?? 1;
+        return new WorkerSet<T>(workerScript, options.elementsPerWorker, options.startDelay);
       case WorkerProcessType.STATIC_POOL:
-        if (Utils.isUndefined(options.poolMaxSize)) {
-          options.poolMaxSize = 16;
-        }
-        return new WorkerStaticPool<T>(workerScript, options.poolMaxSize);
+        options.poolMaxSize = options.poolMaxSize ?? 16;
+        return new WorkerStaticPool<T>(workerScript, options.poolMaxSize, options.startDelay, options.poolOptions);
       case WorkerProcessType.DYNAMIC_POOL:
-        if (Utils.isUndefined(options.poolMinSize)) {
-          options.poolMinSize = 4;
-        }
-        if (Utils.isUndefined(options.poolMaxSize)) {
-          options.poolMaxSize = 16;
-        }
-        return new WorkerDynamicPool<T>(workerScript, options.poolMinSize, options.poolMaxSize);
+        options.poolMinSize = options.poolMinSize ?? 4;
+        options.poolMaxSize = options.poolMaxSize ?? 16;
+        return new WorkerDynamicPool<T>(workerScript, options.poolMinSize, options.poolMaxSize, options.startDelay, options.poolOptions);
       default:
         return null;
     }
index bf8b70210cc289efd0db0e631b12cf72d7099e4a..21f9f482997a6ffad898b39e2bcb6c2d11af46cf 100644 (file)
@@ -1,6 +1,5 @@
 import { WorkerEvents, WorkerSetElement } from '../types/Worker';
 
-import Constants from '../utils/Constants';
 import Utils from '../utils/Utils';
 import { Worker } from 'worker_threads';
 import WorkerAbstract from './WorkerAbstract';
@@ -14,9 +13,10 @@ export default class WorkerSet<T> extends WorkerAbstract {
    *
    * @param {string} workerScript
    * @param {number} maxElementsPerWorker
+   * @param {number} workerStartDelay
    */
-  constructor(workerScript: string, maxElementsPerWorker = 1) {
-    super(workerScript);
+  constructor(workerScript: string, maxElementsPerWorker = 1, workerStartDelay?: number) {
+    super(workerScript, workerStartDelay);
     this.workerSet = new Set<WorkerSetElement>();
     this.maxElementsPerWorker = maxElementsPerWorker;
   }
@@ -27,7 +27,7 @@ export default class WorkerSet<T> extends WorkerAbstract {
 
   /**
    *
-   * @param elementData
+   * @param {T} elementData
    * @returns {Promise<void>}
    * @public
    */
@@ -38,7 +38,7 @@ export default class WorkerSet<T> extends WorkerAbstract {
     if (this.getLastWorkerSetElement().numberOfWorkerElements >= this.maxElementsPerWorker) {
       this.startWorker();
       // Start worker sequentially to optimize memory at startup
-      await Utils.sleep(Constants.START_WORKER_DELAY);
+      await Utils.sleep(this.workerStartDelay);
     }
     this.getLastWorker().postMessage({ id: WorkerEvents.START_WORKER_ELEMENT, workerData: elementData });
     this.getLastWorkerSetElement().numberOfWorkerElements++;
@@ -52,7 +52,7 @@ export default class WorkerSet<T> extends WorkerAbstract {
   public async start(): Promise<void> {
     this.startWorker();
     // Start worker sequentially to optimize memory at startup
-    await Utils.sleep(Constants.START_WORKER_DELAY);
+    await Utils.sleep(this.workerStartDelay);
   }
 
   /**
@@ -98,7 +98,7 @@ export default class WorkerSet<T> extends WorkerAbstract {
   private getWorkerSetElementByWorker(worker: Worker): WorkerSetElement {
     let workerSetElt: WorkerSetElement;
     this.workerSet.forEach((workerSetElement) => {
-      if (JSON.stringify(workerSetElement.worker) === JSON.stringify(worker)) {
+      if (workerSetElement.worker.threadId === worker.threadId) {
         workerSetElt = workerSetElement;
       }
     });
index 6421762918cc1ce9986a277cb1e46e58a5e16ccc..7a304b707d62b0083c98ce82795921f5ff92072c 100644 (file)
@@ -1,6 +1,5 @@
 import { FixedThreadPool, PoolOptions } from 'poolifier';
 
-import Constants from '../utils/Constants';
 import Utils from '../utils/Utils';
 import { Worker } from 'worker_threads';
 import WorkerAbstract from './WorkerAbstract';
@@ -14,17 +13,19 @@ export default class WorkerStaticPool<T> extends WorkerAbstract {
    *
    * @param {string} workerScript
    * @param {number} numberOfThreads
+   * @param {number} startWorkerDelay
+   * @param {PoolOptions} opts
    */
-  constructor(workerScript: string, numberOfThreads: number) {
-    super(workerScript);
-    this.pool = StaticPool.getInstance(numberOfThreads, this.workerScript);
+  constructor(workerScript: string, numberOfThreads: number, startWorkerDelay?: number, opts?: PoolOptions<Worker>) {
+    super(workerScript, startWorkerDelay);
+    this.pool = StaticPool.getInstance(numberOfThreads, this.workerScript, opts);
   }
 
   get size(): number {
     return this.pool.workers.length;
   }
 
-  get maxElementsPerWorker(): number {
+  get maxElementsPerWorker(): number | null {
     return null;
   }
 
@@ -47,14 +48,14 @@ export default class WorkerStaticPool<T> extends WorkerAbstract {
 
   /**
    *
-   * @param elementData
+   * @param {T} elementData
    * @returns {Promise<void>}
    * @public
    */
   public async addElement(elementData: T): Promise<void> {
     await this.pool.execute(elementData);
     // Start worker sequentially to optimize memory at startup
-    await Utils.sleep(Constants.START_WORKER_DELAY);
+    await Utils.sleep(this.workerStartDelay);
   }
 }
 
@@ -65,17 +66,14 @@ class StaticPool extends FixedThreadPool<WorkerData> {
     super(numberOfThreads, workerScript, opts);
   }
 
-  public static getInstance(numberOfThreads: number, workerScript: string): StaticPool {
+  public static getInstance(numberOfThreads: number, workerScript: string, opts?: PoolOptions<Worker>): StaticPool {
     if (!StaticPool.instance) {
-      StaticPool.instance = new StaticPool(numberOfThreads, workerScript,
-        {
-          exitHandler: (code) => {
-            if (code !== 0) {
-              console.error(`Worker stopped with exit code ${code}`);
-            }
-          }
+      opts.exitHandler = opts?.exitHandler ?? ((code) => {
+        if (code !== 0) {
+          console.error(`Worker stopped with exit code ${code}`);
         }
-      );
+      });
+      StaticPool.instance = new StaticPool(numberOfThreads, workerScript, opts);
     }
     return StaticPool.instance;
   }
index dfad95543fe2dd2882af1e250795e9d49b41e888..1fd8e1cd786832a6445175adae334c9e724b2759 100644 (file)
@@ -5,9 +5,9 @@
     /* Basic Options */
     // "incremental": true,                   /* Enable incremental compilation */
     "target": "es2020",                       /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
-    "module": "es2015",                       /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
+    "module": "es2020",                       /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
     "lib": [
-      "es7"
+      "es2020"
     ],                                        /* Specify library files to be included in the compilation. */
     // "allowJs": true,                       /* Allow javascript files to be compiled. */
     // "checkJs": true,                       /* Report errors in .js files. */
@@ -43,7 +43,7 @@
     // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
 
     /* Module Resolution Options */
-    // "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
+    "moduleResolution": "node",               /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
     // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
     // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
     // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */