diff --git a/.gitignore b/.gitignore index 12d0171d..f58d9ee8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ Output node_modules /client/TODO.txt /client/public/javascripts/bundle.js -!client/bin \ No newline at end of file +!client/bin +/client/public/plugins diff --git a/client/src/@types/dom.d.ts b/client/@types/dom.d.ts similarity index 89% rename from client/src/@types/dom.d.ts rename to client/@types/dom.d.ts index 7fea9ff0..4d8080e9 100644 --- a/client/src/@types/dom.d.ts +++ b/client/@types/dom.d.ts @@ -29,17 +29,8 @@ declare global { listener: (this: Document, ev: CustomEventMap[K]) => void): void; dispatchEvent(ev: CustomEventMap[K]): void; } + + function getOlympusPlugin(): OlympusPlugin; } -export interface ConfigParameters { - port: number; - address: string; -} - -export interface ContextMenuOption { - tooltip: string; - src: string; - callback: CallableFunction; -} - -export { }; \ No newline at end of file +export { }; diff --git a/client/@types/olympus.d.ts b/client/@types/olympus.d.ts new file mode 100644 index 00000000..d9856110 --- /dev/null +++ b/client/@types/olympus.d.ts @@ -0,0 +1,267 @@ +interface OlympusPlugin { + getName: () => string; + initialize: (any) => boolean; +} + +declare global { + function getOlympusPlugin(): OlympusPlugin; +} + +interface ConfigurationOptions { + port: number; + address: string; +} + +interface ContextMenuOption { + tooltip: string; + src: string; + callback: CallableFunction; +} + +interface AirbasesData { + airbases: { [key: string]: any }, + sessionHash: string; + time: number; +} + +interface BullseyesData { + bullseyes: { [key: string]: { latitude: number, longitude: number, coalition: string } }, + sessionHash: string; + time: number; +} + +interface MissionData { + mission: { + theatre: string, + dateAndTime: DateAndTime; + commandModeOptions: CommandModeOptions; + coalitions: { red: string[], blue: string[] } = { }; + } + time: number; + sessionHash: string; +} + +interface CommandModeOptions { + commandMode: string; + restrictSpawns: boolean; + restrictToCoalition: boolean; + setupTime: number; + spawnPoints: { + red: number, + blue: number + }, + eras: string[] +} + +interface DateAndTime { + date: { Year: number, Month: number, Day: number }; + time: { h: number, m: number, s: number }; + elapsedTime: number; + startTime: number; +} + +interface LogData { + logs: { [key: string]: string }, + sessionHash: string; + time: number; +} + +interface ServerRequestOptions { + time?: number; + commandHash?: string; +} + +interface UnitSpawnTable { + unitType: string, + location: latlng, + altitude?: number, + loadout?: string, + liveryID: string +} + +interface ObjectIconOptions { + showState: boolean, + showVvi: boolean, + showHotgroup: boolean, + showUnitIcon: boolean, + showShortLabel: boolean, + showFuel: boolean, + showAmmo: boolean, + showSummary: boolean, + showCallsign: boolean, + rotateToHeading: boolean +} + +interface GeneralSettings { + prohibitJettison: boolean; + prohibitAA: boolean; + prohibitAG: boolean; + prohibitAfterburner: boolean; + prohibitAirWpn: boolean; +} + +interface TACAN { + isOn: boolean; + channel: number; + XY: string; + callsign: string; +} + +interface Radio { + frequency: number; + callsign: number; + callsignNumber: number; +} + +interface Ammo { + quantity: number, + name: string, + guidance: number, + category: number, + missileCategory: number +} + +interface Contact { + ID: number, + detectionMethod: number +} + +interface Offset { + x: number, + y: number, + z: number +} + +interface UnitData { + category: string, + ID: number; + alive: boolean; + human: boolean; + controlled: boolean; + coalition: string; + country: number; + name: string; + unitName: string; + groupName: string; + state: string; + task: string; + hasTask: boolean; + position: LatLng; + speed: number; + heading: number; + isTanker: boolean; + isAWACS: boolean; + onOff: boolean; + followRoads: boolean; + fuel: number; + desiredSpeed: number; + desiredSpeedType: string; + desiredAltitude: number; + desiredAltitudeType: string; + leaderID: number; + formationOffset: Offset; + targetID: number; + targetPosition: LatLng; + ROE: string; + reactionToThreat: string; + emissionsCountermeasures: string; + TACAN: TACAN; + radio: Radio; + generalSettings: GeneralSettings; + ammo: Ammo[]; + contacts: Contact[]; + activePath: LatLng[]; + isLeader: boolean; +} + +interface LoadoutItemBlueprint { + name: string; + quantity: number; + effectiveAgainst?: string; +} + +interface LoadoutBlueprint { + fuel: number; + items: LoadoutItemBlueprint[]; + roles: string[]; + code: string; + name: string; +} + +interface UnitBlueprint { + name: string; + coalition: string; + era: string; + label: string; + shortLabel: string; + type?: string; + range?: string; + loadouts?: LoadoutBlueprint[]; + filename?: string; + liveries?: { [key: string]: { name: string, countries: string[] } }; + cost?: number; +} + +interface UnitSpawnOptions { + roleType: string; + name: string; + latlng: LatLng; + coalition: string; + count: number; + country: string; + loadout: LoadoutBlueprint | undefined; + airbase: Airbase | undefined; + liveryID: string | undefined; + altitude: number | undefined; +} + +interface AirbaseOptions { + name: string, + position: L.LatLng +} + +interface AirbaseChartData { + elevation: string, + ICAO: string, + TACAN: string, + runways: AirbaseChartRunwayData[] +} + +interface AirbaseChartRunwayData { + headings: AirbaseChartRunwayHeadingData[], + length: string +} + +interface AirbaseChartRunwayHeadingData { + [index: string]: { + magHeading: string, + ILS: string + } +} + +interface Listener { + callback: CallableFunction; + name?: string +} + +interface ShortcutOptions { + altKey?: boolean; + callback: CallableFunction; + ctrlKey?: boolean; + name?: string; + shiftKey?: boolean; +} + +interface KeyboardShortcutOptions extends ShortcutOptions { + code: string; + event?: "keydown" | "keyup"; +} + +interface MouseShortcutOptions extends ShortcutOptions { + button: number; + event: "mousedown" | "mouseup"; +} + +interface Manager { + add: CallableFunction; +} \ No newline at end of file diff --git a/client/app.js b/client/app.js index 651c2b73..1b2edaa9 100644 --- a/client/app.js +++ b/client/app.js @@ -10,6 +10,7 @@ var indexRouter = require('./routes/index'); var uikitRouter = require('./routes/uikit'); var usersRouter = require('./routes/users'); var resourcesRouter = require('./routes/resources'); +var pluginsRouter = require('./routes/plugins'); var app = express(); @@ -22,6 +23,7 @@ app.use(express.static(path.join(__dirname, 'public'))); app.use('/', indexRouter); app.use('/api/atc', atcRouter); app.use('/api/airbases', airbasesRouter); +app.use('/plugins', pluginsRouter) app.use('/users', usersRouter); app.use('/uikit', uikitRouter); app.use('/resources', resourcesRouter); diff --git a/client/demo.js b/client/demo.js index 758754d9..99c65f9a 100644 --- a/client/demo.js +++ b/client/demo.js @@ -444,7 +444,7 @@ class DemoDataGenerator { var auth = req.get("Authorization"); if (auth) { - var username = atob(auth.replace("Basic ", "")).split(":")[0]; + var username = Buffer.from(auth.replace("Basic ", ""), 'base64').toString('binary').split(":")[0]; switch (username) { case "admin": ret.mission.commandModeOptions.commandMode = "Game master"; diff --git a/client/package-lock.json b/client/package-lock.json index 7e55d2aa..8cdc6ee4 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -38,10 +38,9 @@ "leaflet-path-drag": "*", "leaflet.nauticscale": "^1.1.0", "nodemon": "^2.0.20", + "requirejs": "^2.3.6", "sortablejs": "^1.15.0", "tsify": "^5.0.4", - "typedoc": "^0.24.8", - "typedoc-umlclass": "^0.7.1", "typescript": "^4.9.4", "watchify": "^4.0.0" } @@ -60,47 +59,48 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", - "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", - "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.17.tgz", + "integrity": "sha512-2EENLmhpwplDux5PSsZnSbnSkB3tZ6QTksgO25xwEL7pIDcNOMhF5v/s6RzwjMZzZzw9Ofc30gHv5ChCC8pifQ==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.4", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.4", - "@babel/types": "^7.21.4", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.22.15", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.22.17", + "@babel/helpers": "^7.22.15", + "@babel/parser": "^7.22.16", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.22.17", + "@babel/types": "^7.22.17", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -110,12 +110,6 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, "node_modules/@babel/core/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -140,12 +134,12 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", + "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", "dev": true, "dependencies": { - "@babel/types": "^7.21.4", + "@babel/types": "^7.22.15", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -155,63 +149,60 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", "dev": true, "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", - "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", "lru-cache": "^5.1.1", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.4.tgz", - "integrity": "sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-member-expression-to-functions": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/helper-split-export-declaration": "^7.18.6" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -221,13 +212,14 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.4.tgz", - "integrity": "sha512-M00OuhU+0GyZ5iBBN9czjugzWrEq2vDpf/zCYHxxf93ul/Q5rv+a5h+/+0WnI1AebHNVtl5bFV0qsJoH23DbfA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.3.1" + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -237,20 +229,19 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", + "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "resolve": "^1.14.2" }, "peerDependencies": { - "@babel/core": "^7.4.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { @@ -277,125 +268,112 @@ "dev": true }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", "dev": true, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", "dev": true, "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz", - "integrity": "sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz", + "integrity": "sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA==", "dev": true, "dependencies": { - "@babel/types": "^7.21.0" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dev": true, "dependencies": { - "@babel/types": "^7.21.4" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz", + "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.15" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.17.tgz", + "integrity": "sha512-bxH77R5gjH3Nkde6/LuncQoLaP16THYPscurp1S8z7S9ZgezCyV3G8Hc+TZiCmY8pz4fp8CvKSgtJMW0FkLAxA==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-wrap-function": "^7.22.17" }, "engines": { "node": ">=6.9.0" @@ -405,194 +383,131 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", - "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz", + "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.20.7", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, "dependencies": { - "@babel/types": "^7.20.2" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", - "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", "dev": true, "dependencies": { - "@babel/types": "^7.20.0" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", - "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.17.tgz", + "integrity": "sha512-nAhoheCMlrqU41tAojw9GpVEKDlTS8r3lzFmF0lP52LwblCPbuFSO7nGIZoIcoU5NIm1ABrna0cJExE4Ay6l2Q==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.17" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz", + "integrity": "sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==", "dev": true, "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -602,12 +517,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz", + "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -617,14 +532,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", - "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz", + "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-proposal-optional-chaining": "^7.20.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -633,232 +548,11 @@ "@babel/core": "^7.13.0" } }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", - "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", - "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz", - "integrity": "sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==", + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, "engines": { "node": ">=6.9.0" }, @@ -866,22 +560,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", @@ -946,12 +624,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", - "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", + "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -960,6 +638,33 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", + "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", @@ -1074,13 +779,47 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", - "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", + "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz", + "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { "node": ">=6.9.0" @@ -1090,14 +829,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", - "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", + "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9" + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1107,12 +846,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", + "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1122,12 +861,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz", - "integrity": "sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz", + "integrity": "sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1136,20 +875,53 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz", - "integrity": "sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==", + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", + "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz", + "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.11", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz", + "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-split-export-declaration": "^7.22.6", "globals": "^11.1.0" }, "engines": { @@ -1160,13 +932,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", - "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", + "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/template": "^7.20.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1176,12 +948,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz", - "integrity": "sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz", + "integrity": "sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1191,13 +963,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", + "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1207,12 +979,28 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", + "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz", + "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1222,13 +1010,29 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", + "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", "dev": true, "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz", + "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1238,12 +1042,12 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz", - "integrity": "sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz", + "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1253,14 +1057,30 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", + "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz", + "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1270,12 +1090,28 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", + "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz", + "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { "node": ">=6.9.0" @@ -1285,12 +1121,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", + "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1300,13 +1136,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", - "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", + "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1316,14 +1152,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz", - "integrity": "sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz", + "integrity": "sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-simple-access": "^7.20.2" + "@babel/helper-module-transforms": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1333,15 +1169,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", - "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz", + "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==", "dev": true, "dependencies": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-identifier": "^7.19.1" + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1351,13 +1187,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", + "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1367,13 +1203,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", - "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1383,12 +1219,63 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", + "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz", + "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz", + "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz", + "integrity": "sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -1398,13 +1285,46 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", + "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz", + "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz", + "integrity": "sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1414,12 +1334,46 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz", - "integrity": "sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz", + "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", + "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz", + "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.11", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { "node": ">=6.9.0" @@ -1429,12 +1383,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", + "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1444,13 +1398,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", - "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz", + "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "regenerator-transform": "^0.15.1" + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" }, "engines": { "node": ">=6.9.0" @@ -1460,12 +1414,12 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", + "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1475,12 +1429,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", + "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1490,13 +1444,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", - "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", + "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1506,12 +1460,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", + "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1521,12 +1475,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", + "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1536,12 +1490,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", + "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1551,12 +1505,28 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz", + "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", + "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1566,13 +1536,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", + "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1581,39 +1551,43 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.21.4.tgz", - "integrity": "sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==", + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", + "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.21.0", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.20.7", - "@babel/plugin-proposal-async-generator-functions": "^7.20.7", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.21.0", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.20.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.20.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.21.0", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.21.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.15.tgz", + "integrity": "sha512-tZFHr54GBkHk6hQuVA8w4Fmq+MSPsfvMG0vPnOYyTnJpyfMqybL8/MbNCPRT9zc2KBO2pe4tq15g6Uno4Jpoag==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.15", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.15", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -1623,45 +1597,62 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.20.7", - "@babel/plugin-transform-async-to-generator": "^7.20.7", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.21.0", - "@babel/plugin-transform-classes": "^7.21.0", - "@babel/plugin-transform-computed-properties": "^7.20.7", - "@babel/plugin-transform-destructuring": "^7.21.3", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.21.0", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.20.11", - "@babel/plugin-transform-modules-commonjs": "^7.21.2", - "@babel/plugin-transform-modules-systemjs": "^7.20.11", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.20.5", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.21.3", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.20.5", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.20.7", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.21.4", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", - "semver": "^6.3.0" + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.15", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-block-scoped-functions": "^7.22.5", + "@babel/plugin-transform-block-scoping": "^7.22.15", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-class-static-block": "^7.22.11", + "@babel/plugin-transform-classes": "^7.22.15", + "@babel/plugin-transform-computed-properties": "^7.22.5", + "@babel/plugin-transform-destructuring": "^7.22.15", + "@babel/plugin-transform-dotall-regex": "^7.22.5", + "@babel/plugin-transform-duplicate-keys": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.11", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.11", + "@babel/plugin-transform-for-of": "^7.22.15", + "@babel/plugin-transform-function-name": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.11", + "@babel/plugin-transform-literals": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.11", + "@babel/plugin-transform-member-expression-literals": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.15", + "@babel/plugin-transform-modules-systemjs": "^7.22.11", + "@babel/plugin-transform-modules-umd": "^7.22.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", + "@babel/plugin-transform-numeric-separator": "^7.22.11", + "@babel/plugin-transform-object-rest-spread": "^7.22.15", + "@babel/plugin-transform-object-super": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.11", + "@babel/plugin-transform-optional-chaining": "^7.22.15", + "@babel/plugin-transform-parameters": "^7.22.15", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.11", + "@babel/plugin-transform-property-literals": "^7.22.5", + "@babel/plugin-transform-regenerator": "^7.22.10", + "@babel/plugin-transform-reserved-words": "^7.22.5", + "@babel/plugin-transform-shorthand-properties": "^7.22.5", + "@babel/plugin-transform-spread": "^7.22.5", + "@babel/plugin-transform-sticky-regex": "^7.22.5", + "@babel/plugin-transform-template-literals": "^7.22.5", + "@babel/plugin-transform-typeof-symbol": "^7.22.5", + "@babel/plugin-transform-unicode-escapes": "^7.22.10", + "@babel/plugin-transform-unicode-property-regex": "^7.22.5", + "@babel/plugin-transform-unicode-regex": "^7.22.5", + "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "@babel/types": "^7.22.15", + "babel-plugin-polyfill-corejs2": "^0.4.5", + "babel-plugin-polyfill-corejs3": "^0.8.3", + "babel-plugin-polyfill-regenerator": "^0.5.2", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -1671,19 +1662,17 @@ } }, "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", "@babel/types": "^7.4.4", "esutils": "^2.0.2" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/regjsgen": { @@ -1693,45 +1682,45 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz", - "integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", + "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", "dev": true, "dependencies": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.17.tgz", + "integrity": "sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.16", + "@babel/types": "^7.22.17", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1763,13 +1752,13 @@ "dev": true }, "node_modules/@babel/types": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", - "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1791,9 +1780,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, "engines": { "node": ">=6.0.0" @@ -1815,30 +1804,24 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, "node_modules/@tanem/svg-injector": { - "version": "10.1.55", - "resolved": "https://registry.npmjs.org/@tanem/svg-injector/-/svg-injector-10.1.55.tgz", - "integrity": "sha512-xh8ejdvjDaH1eddZC0CdI45eeid4BIU2ppjNEhiTiWMYcLGT19KWjbES/ttDS4mq9gIAQfXx57g5zimEVohqYA==", + "version": "10.1.62", + "resolved": "https://registry.npmjs.org/@tanem/svg-injector/-/svg-injector-10.1.62.tgz", + "integrity": "sha512-74/VTSpUfbdPstcIqzLKLcSp/DXfsrFpzxnh/FGGQFEqQZ59IqgFqjB2TALGwZihmepiC5JobKRA+hRnrjmzFA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.21.5", + "@babel/runtime": "^7.22.6", "content-type": "^1.0.5", - "tslib": "^2.5.0" + "tslib": "^2.6.1" } }, "node_modules/@turf/along": { @@ -3531,24 +3514,24 @@ "dev": true }, "node_modules/@types/leaflet": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.0.tgz", - "integrity": "sha512-7LeOSj7EloC5UcyOMo+1kc3S1UT3MjJxwqsMT1d2PTyvQz53w0Y0oSSk9nwZnOZubCmBvpSNGceucxiq+ZPEUw==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-kfwgQf4eOxoe/tD9CaKQrBKHbc7VpyfJOG5sxsQtkH+ML9xYa8hUC3UMa0wU1pKfciJtO0pU9g9XbWhPo7iBCA==", "dev": true, "dependencies": { "@types/geojson": "*" } }, "node_modules/@types/node": { - "version": "18.16.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.1.tgz", - "integrity": "sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA==", + "version": "18.17.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.15.tgz", + "integrity": "sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA==", "dev": true }, "node_modules/@types/sortablejs": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.0.tgz", - "integrity": "sha512-qrhtM7M41EhH4tZQTNw2/RJkxllBx3reiJpTbgWCM2Dx0U1sZ6LwKp9lfNln9uqE26ZMKUaPEYaD4rzvOWYtZw==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.2.tgz", + "integrity": "sha512-mOIv/EnPMzAZAVbuh9uGjOZ1BBdimP9Y6IPGntsvQJtko5yapSDKB7GwB3AOlF5N3bkpk4sBwQRpS3aEkiUbaA==", "dev": true }, "node_modules/@types/svg-injector": { @@ -3623,17 +3606,15 @@ "dev": true }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4" } }, "node_modules/any-promise": { @@ -3679,28 +3660,28 @@ "dev": true }, "node_modules/assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", + "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", "dev": true, "dependencies": { - "object-assign": "^4.1.1", - "util": "0.10.3" + "object.assign": "^4.1.4", + "util": "^0.10.4" } }, "node_modules/assert/node_modules/inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "node_modules/assert/node_modules/util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", "dev": true, "dependencies": { - "inherits": "2.0.1" + "inherits": "2.0.3" } }, "node_modules/async": { @@ -3811,42 +3792,42 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", + "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.2", + "semver": "^6.3.1" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz", + "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" + "@babel/helper-define-polyfill-provider": "^0.4.2", + "core-js-compat": "^3.31.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", + "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3" + "@babel/helper-define-polyfill-provider": "^0.4.2" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-runtime": { @@ -3982,6 +3963,11 @@ "node": ">= 0.8" } }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -4205,16 +4191,10 @@ "safe-buffer": "^5.2.0" } }, - "node_modules/browserify-sign/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "node_modules/browserify-sign/node_modules/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==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "dependencies": { "inherits": "^2.0.3", @@ -4225,26 +4205,6 @@ "node": ">= 6" } }, - "node_modules/browserify-sign/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/browserify-zlib": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", @@ -4255,9 +4215,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", "dev": true, "funding": [ { @@ -4267,13 +4227,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" }, "bin": { "browserslist": "cli.js" @@ -4338,9 +4302,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001481", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz", - "integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==", + "version": "1.0.30001534", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001534.tgz", + "integrity": "sha512-vlPVrhsCS7XaSh2VvWluIQEzVhefrUQcEsQWSS5A5V+dM07uv1qHeQzAOTGIMy9i3e9bH15+muvI/UHojVgS/Q==", "dev": true, "funding": [ { @@ -4358,18 +4322,17 @@ ] }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=4" } }, "node_modules/chokidar": { @@ -4424,20 +4387,19 @@ } }, "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "color-name": "1.1.3" } }, "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, "node_modules/combine-source-map": { "version": "0.8.0", @@ -4451,6 +4413,12 @@ "source-map": "~0.5.3" } }, + "node_modules/combine-source-map/node_modules/convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", + "dev": true + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -4531,6 +4499,76 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/concurrently/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/concurrently/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concurrently/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/concurrently/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -4575,9 +4613,9 @@ } }, "node_modules/convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true }, "node_modules/cookie": { @@ -4614,12 +4652,12 @@ "hasInstallScript": true }, "node_modules/core-js-compat": { - "version": "3.30.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.30.1.tgz", - "integrity": "sha512-d690npR7MC6P0gq4npTl5n2VQeNAmUrJ90n+MHiKS7W2+xno4o3F5GDEuylSdi6EJ3VssibSGXOa1r3YXD3Mhw==", + "version": "3.32.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.2.tgz", + "integrity": "sha512-+GjlguTDINOijtVRUxrQOv3kfu9rl+qPNdX2LTbJ/ZyVTuxK+ksVSAGX1nHstu4hrv1En/uPTtWgq2gI5wt4AQ==", "dev": true, "dependencies": { - "browserslist": "^4.21.5" + "browserslist": "^4.21.10" }, "funding": { "type": "opencollective", @@ -4731,10 +4769,13 @@ "dev": true }, "node_modules/date-fns": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", - "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, "engines": { "node": ">=0.11" }, @@ -4777,12 +4818,27 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "node_modules/define-data-property": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz", + "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", "dev": true, "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" }, @@ -4832,9 +4888,9 @@ } }, "node_modules/des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", "dev": true, "dependencies": { "inherits": "^2.0.1", @@ -4916,9 +4972,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/ejs": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", - "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", "dependencies": { "jake": "^10.8.5" }, @@ -4930,9 +4986,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.371", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.371.tgz", - "integrity": "sha512-jlBzY4tFcJaiUjzhRTCWAqRvTO/fWzjA3Bls0mykzGZ7zvcMP7h05W6UcgzfT9Ca1SW2xyKDOFRyI0pQeRNZGw==", + "version": "1.4.520", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.520.tgz", + "integrity": "sha512-Frfus2VpYADsrh1lB3v/ft/WVFlVzOIm+Q0p7U7VqHI6qr7NWHYKe+Wif3W50n7JAFoBsWVsoU0+qDks6WQ60g==", "dev": true }, "node_modules/elliptic": { @@ -4956,12 +5012,6 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true }, - "node_modules/elliptic/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -5132,6 +5182,11 @@ "node": ">= 0.6" } }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", @@ -5155,9 +5210,9 @@ } }, "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -5237,9 +5292,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -5333,13 +5388,14 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "dev": true, "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3" }, "funding": { @@ -5433,11 +5489,12 @@ } }, "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/has-property-descriptors": { @@ -5452,6 +5509,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -5493,16 +5562,10 @@ "node": ">=4" } }, - "node_modules/hash-base/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "node_modules/hash-base/node_modules/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==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "dependencies": { "inherits": "^2.0.3", @@ -5513,26 +5576,6 @@ "node": ">= 6" } }, - "node_modules/hash-base/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -5577,6 +5620,11 @@ "node": ">= 0.6" } }, + "node_modules/http-errors/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, "node_modules/https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", @@ -5631,9 +5679,10 @@ } }, "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "node_modules/inline-source-map": { "version": "0.6.2", @@ -5735,9 +5784,9 @@ } }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -5832,16 +5881,12 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.11" }, "engines": { "node": ">= 0.4" @@ -5863,14 +5908,14 @@ "dev": true }, "node_modules/jake": { - "version": "10.8.5", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", - "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", - "filelist": "^1.0.1", - "minimatch": "^3.0.4" + "filelist": "^1.0.4", + "minimatch": "^3.1.2" }, "bin": { "jake": "bin/cli.js" @@ -5879,6 +5924,70 @@ "node": ">=10" } }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jake/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5951,9 +6060,9 @@ } }, "node_modules/leaflet": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.3.tgz", - "integrity": "sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", "dev": true }, "node_modules/leaflet-control-mini-map": { @@ -6129,9 +6238,9 @@ } }, "node_modules/mingo": { - "version": "6.2.7", - "resolved": "https://registry.npmjs.org/mingo/-/mingo-6.2.7.tgz", - "integrity": "sha512-r+yKmrZ+6SjwGxSot+/3S8sP9+LCxWNueR6xppMx7BzV60OegjbeklWAf/UveyQi8PDW8g/mwrQSHZVY/5jBJQ==" + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/mingo/-/mingo-6.4.4.tgz", + "integrity": "sha512-GtgwqyBVLxKf8tSvN26TjbK+XAUW5HlWR3D7qBsBh9urQyZznqG2BOx90t3MXklpSxawjvaANiWFUCIxd9xa7w==" }, "node_modules/minimalistic-assert": { "version": "1.0.1", @@ -6157,9 +6266,9 @@ } }, "node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6229,15 +6338,15 @@ } }, "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, "node_modules/nodemon": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", - "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -6271,15 +6380,6 @@ "ms": "^2.1.1" } }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/nodemon/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -6287,26 +6387,14 @@ "dev": true }, "node_modules/nodemon/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" } }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", @@ -6340,6 +6428,15 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-is": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", @@ -6365,6 +6462,24 @@ "node": ">= 0.4" } }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -6641,16 +6756,6 @@ "node": ">=0.6" } }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", @@ -6735,9 +6840,9 @@ } }, "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "dependencies": { "core-util-is": "~1.0.0", @@ -6749,6 +6854,12 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/readable-stream/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -6789,29 +6900,29 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", "dev": true }, "node_modules/regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dev": true, "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "set-function-name": "^2.0.0" }, "engines": { "node": ">= 0.4" @@ -6867,13 +6978,26 @@ "node": ">=0.10.0" } }, + "node_modules/requirejs": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", + "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==", + "dev": true, + "bin": { + "r_js": "bin/r.js", + "r.js": "bin/r.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -6901,18 +7025,33 @@ "dev": true }, "node_modules/rxjs": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", - "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, "dependencies": { "tslib": "^2.1.0" } }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -6931,9 +7070,9 @@ } }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -6976,6 +7115,20 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", @@ -7004,26 +7157,14 @@ } }, "node_modules/shell-quote": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz", - "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shiki": { - "version": "0.14.4", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz", - "integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==", - "dev": true, - "dependencies": { - "ansi-sequence-parser": "^1.1.0", - "jsonc-parser": "^3.2.0", - "vscode-oniguruma": "^1.7.0", - "vscode-textmate": "^8.0.0" - } - }, "node_modules/simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -7136,16 +7277,10 @@ "readable-stream": "^3.5.0" } }, - "node_modules/stream-browserify/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "node_modules/stream-browserify/node_modules/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==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "dependencies": { "inherits": "^2.0.3", @@ -7187,16 +7322,10 @@ "xtend": "^4.0.2" } }, - "node_modules/stream-http/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "node_modules/stream-http/node_modules/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==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "dependencies": { "inherits": "^2.0.3", @@ -7226,26 +7355,6 @@ "safe-buffer": "~5.2.0" } }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -7303,14 +7412,15 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -7469,9 +7579,9 @@ } }, "node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, "node_modules/tty-browserify": { @@ -7565,9 +7675,9 @@ } }, "node_modules/typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -7687,20 +7797,29 @@ } }, "node_modules/url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.2.tgz", + "integrity": "sha512-7yIgNnrST44S7PJ5+jXbdIupfU1nWUdQJBFBeJRclPXiWgCvrSq5Frw8lr/i//n5sqDfzoKmBymMS81l4U/7cg==", "dev": true, "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" + "punycode": "^1.4.1", + "qs": "^6.11.2" } }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", - "dev": true + "node_modules/url/node_modules/qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/util": { "version": "0.12.5", @@ -7777,9 +7896,9 @@ } }, "node_modules/watchify/node_modules/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==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "dependencies": { "inherits": "^2.0.3", @@ -7800,17 +7919,16 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -7836,6 +7954,39 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -7867,9 +8018,9 @@ "dev": true }, "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { "cliui": "^8.0.1", @@ -10607,12 +10758,6 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, - "ansi-sequence-parser": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", - "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", - "dev": true - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -10921,15 +11066,6 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, - "binary-split": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/binary-split/-/binary-split-1.0.5.tgz", - "integrity": "sha512-AQ5fcBrUU5hoIafkEvNKqxT+2xbqlSqAXef6IdCQr5wpHu9E7NGM6rTAlYJYbtxvAvjfx8nJkBy6rNlbPPI+Pw==", - "dev": true, - "requires": { - "through2": "^2.0.3" - } - }, "bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", @@ -11543,15 +11679,6 @@ "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", "dev": true }, - "dbly-linked-list": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/dbly-linked-list/-/dbly-linked-list-0.3.4.tgz", - "integrity": "sha512-327vOlwspi9i1T3Kc9yZhRUR8qDdgMQ4HmXsFDDCQ/HTc3sNe7gnF5b0UrsnaOJ0rvmG7yBZpK0NoOux9rKYKw==", - "dev": true, - "requires": { - "lodash.isequal": "^4.5.0" - } - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -12468,12 +12595,6 @@ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -12542,12 +12663,6 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "dev": true - }, "lodash.memoize": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", @@ -12572,23 +12687,11 @@ "yallist": "^3.0.2" } }, - "lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true - }, "map-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==" }, - "marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true - }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -12973,22 +13076,6 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, - "plantuml-encoder": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/plantuml-encoder/-/plantuml-encoder-1.4.0.tgz", - "integrity": "sha512-sxMwpDw/ySY1WB2CE3+IdMuEcWibJ72DDOsXLkSmEaSzwEUaYBT6DWgOfBiHGCux4q433X6+OEFWjlVqp7gL6g==", - "dev": true - }, - "plantuml-pipe": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/plantuml-pipe/-/plantuml-pipe-1.5.0.tgz", - "integrity": "sha512-a4brAspbSlQYDdzLtDulB7ZQOGI5JC3Kyk7cTo8kDrM2gOQcarXkP/fN0mR+gD3srS9BMI06rOQKkvhrFpqYzg==", - "dev": true, - "requires": { - "binary-split": "^1.0.5", - "split2": "^4.2.0" - } - }, "point-in-polygon": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz", @@ -13016,12 +13103,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -13082,15 +13163,6 @@ "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", "dev": true }, - "queue-fifo": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/queue-fifo/-/queue-fifo-0.2.6.tgz", - "integrity": "sha512-rwlnZHAaTmWEGKC7ziasK8u4QnZW/uN6kSiG+tHNf/1GA+R32FArZi18s3SYUpKcA0Y6jJoUDn5GT3Anoc2mWw==", - "dev": true, - "requires": { - "dbly-linked-list": "0.3.4" - } - }, "quickselect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz", @@ -13387,18 +13459,6 @@ "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==", "dev": true }, - "shiki": { - "version": "0.14.4", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz", - "integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==", - "dev": true, - "requires": { - "ansi-sequence-parser": "^1.1.0", - "jsonc-parser": "^3.2.0", - "vscode-oniguruma": "^1.7.0", - "vscode-textmate": "^8.0.0" - } - }, "simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -13460,12 +13520,6 @@ "through": "2" } }, - "split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true - }, "statuses": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", @@ -13781,50 +13835,6 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "dev": true }, - "typedoc": { - "version": "0.24.8", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", - "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", - "dev": true, - "requires": { - "lunr": "^2.3.9", - "marked": "^4.3.0", - "minimatch": "^9.0.0", - "shiki": "^0.14.1" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "typedoc-umlclass": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/typedoc-umlclass/-/typedoc-umlclass-0.7.1.tgz", - "integrity": "sha512-nHEPjbda1oIZ5lKNMainzi93UB1FyyMNoFWjNlipjK/Adx/RtepJdaGdIrZ8EgtuWGi7pW+xP8jaRmb40vj/9w==", - "dev": true, - "requires": { - "plantuml-encoder": "^1.4.0", - "plantuml-pipe": "^1.5.0", - "progress": "^2.0.3", - "queue-fifo": "^0.2.6" - } - }, "typescript": { "version": "4.9.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", @@ -13952,18 +13962,6 @@ "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", "dev": true }, - "vscode-oniguruma": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", - "dev": true - }, - "vscode-textmate": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", - "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", - "dev": true - }, "watchify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/watchify/-/watchify-4.0.0.tgz", diff --git a/client/package.json b/client/package.json index 39ac24e4..c4d29b30 100644 --- a/client/package.json +++ b/client/package.json @@ -41,8 +41,10 @@ "leaflet-path-drag": "*", "leaflet.nauticscale": "^1.1.0", "nodemon": "^2.0.20", + "requirejs": "^2.3.6", "sortablejs": "^1.15.0", "tsify": "^5.0.4", + "tslib": "latest", "typedoc": "^0.24.8", "typedoc-umlclass": "^0.7.1", "typescript": "^4.9.4", diff --git a/client/plugins/controltips/copy.bat b/client/plugins/controltips/copy.bat new file mode 100644 index 00000000..e0a9d89d --- /dev/null +++ b/client/plugins/controltips/copy.bat @@ -0,0 +1,5 @@ +mkdir .\\..\\..\\public\\plugins\\controltipsplugin + +copy .\\index.js .\\..\\..\\public\\plugins\\controltipsplugin\\index.js +copy .\\plugin.json .\\..\\..\\public\\plugins\\controltipsplugin\\plugin.json +copy .\\style.css .\\..\\..\\public\\plugins\\controltipsplugin\\style.css \ No newline at end of file diff --git a/client/plugins/controltips/index.js b/client/plugins/controltips/index.js new file mode 100644 index 00000000..37ad45af --- /dev/null +++ b/client/plugins/controltips/index.js @@ -0,0 +1,256 @@ +(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i { + __classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this); + }); + __classPrivateFieldGet(this, _ControlTipsPlugin_shortcutManager, "f").onKeyUp(() => { + __classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this); + }); + document.addEventListener("airbaseMouseover", (ev) => { + __classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, true, "f"); + __classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this); + }); + document.addEventListener("airbaseMouseout", (ev) => { + __classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, false, "f"); + __classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this); + }); + document.addEventListener("unitDeselection", (ev) => { + __classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this); + }); + document.addEventListener("unitMouseover", (ev) => { + __classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, true, "f"); + __classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this); + }); + document.addEventListener("unitMouseout", (ev) => { + __classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, false, "f"); + __classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this); + }); + document.addEventListener("unitSelection", (ev) => { + __classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this); + }); + document.addEventListener("mapVisibilityOptionsChanged", () => { + this.toggle(!__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getMap().getVisibilityOptions()[SHOW_CONTROL_TIPS]); + }); + __classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this); + __classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getMap().addVisibilityOption(SHOW_CONTROL_TIPS, true); + return true; + } + getElement() { + return __classPrivateFieldGet(this, _ControlTipsPlugin_element, "f"); + } + toggle(bool) { + this.getElement().classList.toggle("hide", bool); + } +} +exports.ControlTipsPlugin = ControlTipsPlugin; +_ControlTipsPlugin_element = new WeakMap(), _ControlTipsPlugin_app = new WeakMap(), _ControlTipsPlugin_shortcutManager = new WeakMap(), _ControlTipsPlugin_cursorIsHoveringOverUnit = new WeakMap(), _ControlTipsPlugin_cursorIsHoveringOverAirbase = new WeakMap(), _ControlTipsPlugin_instances = new WeakSet(), _ControlTipsPlugin_updateTips = function _ControlTipsPlugin_updateTips() { + const combos = [ + { + "keys": [], + "tips": [ + { + "key": `SHIFT`, + "action": `Box select`, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false, + "showIfUnitSelected": false + }, + { + "key": `Mouse1`, + "action": `Deselect`, + "showIfUnitSelected": true + }, + { + "key": `Mouse1+drag`, + "action": `Move map`, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false, + "showIfUnitSelected": false + }, + { + "key": `Mouse2`, + "action": `Spawn menu`, + "showIfUnitSelected": false, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false + }, + { + "key": `Mouse2`, + "action": `Quick options`, + "showIfUnitSelected": false, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": true + }, + { + "key": `Mouse2`, + "action": `Airbase menu`, + "showIfUnitSelected": false, + "showIfHoveringOverAirbase": true, + "showIfHoveringOverUnit": false + }, + { + "key": `Mouse2`, + "action": `Set first waypoint`, + "showIfHoveringOverAirbase": false, + "showIfUnitSelected": true, + "unitsMustBeControlled": true + }, + { + "key": "CTRL+Mouse2", + "action": "Add waypoint", + "showIfUnitSelected": true, + "showIfHoveringOverAirbase": false, + "unitsMustBeControlled": true + }, + { + "key": `Mouse2 (hold)`, + "action": `Point operations`, + "showIfUnitSelected": true, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false, + "unitsMustBeControlled": true + }, + { + "key": "CTRL", + "action": " Pin tool", + "showIfUnitSelected": false, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false, + "unitsMustBeControlled": true + }, + { + "key": "CTRL+Mouse2", + "action": " Airbase menu", + "showIfUnitSelected": true, + "showIfHoveringOverAirbase": true, + "unitsMustBeControlled": true + }, + { + "key": `Delete`, + "action": `Delete unit`, + "showIfHoveringOverAirbase": false, + "showIfUnitSelected": true + } + ] + }, + { + "keys": ["ControlLeft"], + "tips": [ + { + "key": `Mouse1`, + "action": "Toggle pin", + "showIfUnitSelected": false, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false + }, + { + "key": `Mouse1`, + "action": "Toggle selection", + "showIfUnitSelected": true, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": true + }, + { + "key": `Mouse2`, + "action": `Add waypoint`, + "showIfHoveringOverAirbase": false, + "showIfUnitSelected": true, + "unitsMustBeControlled": true + }, + { + "key": `Mouse2`, + "action": `Airbase menu`, + "showIfHoveringOverAirbase": true, + "showIfUnitSelected": true, + "unitsMustBeControlled": true + } + ] + }, + { + "keys": ["ShiftLeft"], + "tips": [ + { + "key": `mouse1+drag`, + "action": "Box select" + } + ] + } + ]; + const currentCombo = combos.find((combo) => __classPrivateFieldGet(this, _ControlTipsPlugin_shortcutManager, "f").keyComboMatches(combo.keys)) || combos[0]; + const element = this.getElement(); + element.innerHTML = ""; + let numSelectedUnits = 0; + let unitSelectionContainsControlled = false; + if (__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getUnitsManager()) { + let selectedUnits = Object.values(__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getUnitsManager().getSelectedUnits()); + numSelectedUnits = selectedUnits.length; + unitSelectionContainsControlled = selectedUnits.some((unit) => unit.getControlled()); + } + currentCombo.tips.forEach((tip) => { + if (numSelectedUnits > 0) { + if (tip.showIfUnitSelected === false) { + return; + } + if (tip.unitsMustBeControlled === true && unitSelectionContainsControlled === false) { + return; + } + } + if (numSelectedUnits === 0 && tip.showIfUnitSelected === true) { + return; + } + if (typeof tip.showIfHoveringOverAirbase === "boolean") { + if (tip.showIfHoveringOverAirbase !== __classPrivateFieldGet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, "f")) { + return; + } + } + if (typeof tip.showIfHoveringOverUnit === "boolean") { + if (tip.showIfHoveringOverUnit !== __classPrivateFieldGet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, "f")) { + return; + } + } + element.innerHTML += `
${tip.key}${tip.action}
`; + }); +}; + +},{}],2:[function(require,module,exports){ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const controltips_1 = require("./controltips"); +globalThis.getOlympusPlugin = () => { + return new controltips_1.ControlTipsPlugin(); +}; + +},{"./controltips":1}]},{},[2]); diff --git a/client/plugins/controltips/package-lock.json b/client/plugins/controltips/package-lock.json new file mode 100644 index 00000000..86c830ed --- /dev/null +++ b/client/plugins/controltips/package-lock.json @@ -0,0 +1,162 @@ +{ + "name": "ControlTipsPlugin", + "version": "v0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "requires": { + "error-ex": "^1.2.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "tsconfig": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-5.0.3.tgz", + "integrity": "sha512-Cq65A3kVp6BbsUgg9DRHafaGmbMb9EhAc7fjWvudNWKjkbWrt43FnrtZt6awshH1R0ocfF2Z0uxock3lVqEgOg==", + "requires": { + "any-promise": "^1.3.0", + "parse-json": "^2.2.0", + "strip-bom": "^2.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "tsify": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/tsify/-/tsify-5.0.4.tgz", + "integrity": "sha512-XAZtQ5OMPsJFclkZ9xMZWkSNyMhMxEPsz3D2zu79yoKorH9j/DT4xCloJeXk5+cDhosEibu4bseMVjyPOAyLJA==", + "requires": { + "convert-source-map": "^1.1.0", + "fs.realpath": "^1.0.0", + "object-assign": "^4.1.0", + "semver": "^6.1.0", + "through2": "^2.0.0", + "tsconfig": "^5.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + } + } +} diff --git a/client/plugins/controltips/package.json b/client/plugins/controltips/package.json new file mode 100644 index 00000000..3b0097a1 --- /dev/null +++ b/client/plugins/controltips/package.json @@ -0,0 +1,10 @@ +{ + "name": "ControlTipsPlugin", + "version": "v0.0.1", + "private": true, + "scripts": { + "build": "browserify ./src/index.ts -p [ tsify --noImplicitAny] > index.js && copy.bat" + }, + "dependencies": {}, + "devDependencies": {} +} diff --git a/client/plugins/controltips/plugin.json b/client/plugins/controltips/plugin.json new file mode 100644 index 00000000..77a1f817 --- /dev/null +++ b/client/plugins/controltips/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "Control Tip Plugin", + "version": "0.0.1", + "description": "This plugin shows useful control tips on the right side of the screen. The tips change dynamically depending on what the user does", + "author": "Peekaboo" +} \ No newline at end of file diff --git a/client/plugins/controltips/src/controltipsplugin.ts b/client/plugins/controltips/src/controltipsplugin.ts new file mode 100644 index 00000000..2eeba8ff --- /dev/null +++ b/client/plugins/controltips/src/controltipsplugin.ts @@ -0,0 +1,259 @@ +const SHOW_CONTROL_TIPS = "Show control tips" + +export class ControlTipsPlugin implements OlympusPlugin { + #element: HTMLElement; + #app: any; + #shortcutManager: any; + #cursorIsHoveringOverUnit: boolean = false; + #cursorIsHoveringOverAirbase: boolean = false; + + constructor() { + this.#element = document.createElement("div"); + this.#element.id = "control-tips-panel"; + document.body.appendChild(this.#element); + } + + getName() { + return "Control Tips Plugin" + } + + initialize(app: any) { + this.#app = app; + + this.#shortcutManager = this.#app.getShortcutManager(); + + this.#shortcutManager.onKeyDown(() => { + this.#updateTips() + }); + + this.#shortcutManager.onKeyUp(() => { + this.#updateTips() + }); + + document.addEventListener("airbaseMouseover", (ev: CustomEventInit) => { + this.#cursorIsHoveringOverAirbase = true; + this.#updateTips(); + }); + + document.addEventListener("airbaseMouseout", (ev: CustomEventInit) => { + this.#cursorIsHoveringOverAirbase = false; + this.#updateTips(); + }); + + document.addEventListener("unitDeselection", (ev: CustomEvent) => { + this.#updateTips(); + }); + + document.addEventListener("unitMouseover", (ev: CustomEventInit) => { + this.#cursorIsHoveringOverUnit = true; + this.#updateTips(); + }); + + document.addEventListener("unitMouseout", (ev: CustomEventInit) => { + this.#cursorIsHoveringOverUnit = false; + this.#updateTips(); + }); + + document.addEventListener("unitSelection", (ev: CustomEvent) => { + this.#updateTips() + }); + + document.addEventListener("mapVisibilityOptionsChanged", () => { + this.toggle( !this.#app.getMap().getVisibilityOptions()[SHOW_CONTROL_TIPS] ); + }); + + this.#updateTips(); + + this.#app.getMap().addVisibilityOption(SHOW_CONTROL_TIPS, true); + + return true; + } + + getElement() { + return this.#element; + } + + toggle(bool?: boolean) { + this.getElement().classList.toggle("hide", bool); + } + + #updateTips() { + const combos: Array = [ + { + "keys": [], + "tips": [ + { + "key": `SHIFT`, + "action": `Box select`, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false, + "showIfUnitSelected": false + }, + { + "key": `Mouse1`, + "action": `Deselect`, + "showIfUnitSelected": true + }, + { + "key": `Mouse1+drag`, + "action": `Move map`, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false, + "showIfUnitSelected": false + }, + { + "key": `Mouse2`, + "action": `Spawn menu`, + "showIfUnitSelected": false, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false + }, + { + "key": `Mouse2`, + "action": `Quick options`, + "showIfUnitSelected": false, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": true + }, + { + "key": `Mouse2`, + "action": `Airbase menu`, + "showIfUnitSelected": false, + "showIfHoveringOverAirbase": true, + "showIfHoveringOverUnit": false + }, + { + "key": `Mouse2`, + "action": `Set first waypoint`, + "showIfHoveringOverAirbase": false, + "showIfUnitSelected": true, + "unitsMustBeControlled": true + }, + { + "key": "CTRL+Mouse2", + "action": "Add waypoint", + "showIfUnitSelected": true, + "showIfHoveringOverAirbase": false, + "unitsMustBeControlled": true + }, + { + "key": `Mouse2 (hold)`, + "action": `Point operations`, + "showIfUnitSelected": true, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false, + "unitsMustBeControlled": true + }, + { + "key": "CTRL", + "action": " Pin tool", + "showIfUnitSelected": false, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false, + "unitsMustBeControlled": true + }, + { + "key": "CTRL+Mouse2", + "action": " Airbase menu", + "showIfUnitSelected": true, + "showIfHoveringOverAirbase": true, + "unitsMustBeControlled": true + }, + { + "key": `Delete`, + "action": `Delete unit`, + "showIfHoveringOverAirbase": false, + "showIfUnitSelected": true + } + ] + }, + { + "keys": ["ControlLeft"], + "tips": [ + { + "key": `Mouse1`, + "action": "Toggle pin", + "showIfUnitSelected": false, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": false + }, + { + "key": `Mouse1`, + "action": "Toggle selection", + "showIfUnitSelected": true, + "showIfHoveringOverAirbase": false, + "showIfHoveringOverUnit": true + }, + { + "key": `Mouse2`, + "action": `Add waypoint`, + "showIfHoveringOverAirbase": false, + "showIfUnitSelected": true, + "unitsMustBeControlled": true + }, + { + "key": `Mouse2`, + "action": `Airbase menu`, + "showIfHoveringOverAirbase": true, + "showIfUnitSelected": true, + "unitsMustBeControlled": true + } + ] + }, + { + "keys": ["ShiftLeft"], + "tips": [ + { + "key": `mouse1+drag`, + "action": "Box select" + } + ] + } + ]; + + const currentCombo: any = combos.find((combo: any) => this.#shortcutManager.keyComboMatches(combo.keys)) || combos[0]; + + const element = this.getElement(); + + element.innerHTML = ""; + + let numSelectedUnits = 0; + let unitSelectionContainsControlled = false; + + if (this.#app.getUnitsManager()) { + let selectedUnits = Object.values(this.#app.getUnitsManager().getSelectedUnits()); + numSelectedUnits = selectedUnits.length; + unitSelectionContainsControlled = selectedUnits.some((unit: any) => unit.getControlled()); + } + + currentCombo.tips.forEach((tip: any) => { + if (numSelectedUnits > 0) { + if (tip.showIfUnitSelected === false) { + return; + } + + if (tip.unitsMustBeControlled === true && unitSelectionContainsControlled === false) { + return; + } + } + + if (numSelectedUnits === 0 && tip.showIfUnitSelected === true) { + return; + } + + if (typeof tip.showIfHoveringOverAirbase === "boolean") { + if (tip.showIfHoveringOverAirbase !== this.#cursorIsHoveringOverAirbase) { + return; + } + } + + if (typeof tip.showIfHoveringOverUnit === "boolean") { + if (tip.showIfHoveringOverUnit !== this.#cursorIsHoveringOverUnit) { + return; + } + } + + element.innerHTML += `
${tip.key}${tip.action}
` + }); + } +} \ No newline at end of file diff --git a/client/plugins/controltips/src/index.ts b/client/plugins/controltips/src/index.ts new file mode 100644 index 00000000..425907e0 --- /dev/null +++ b/client/plugins/controltips/src/index.ts @@ -0,0 +1,5 @@ +import { ControlTipsPlugin } from "./controltipsplugin"; + +globalThis.getOlympusPlugin = () => { + return new ControlTipsPlugin(); +} \ No newline at end of file diff --git a/client/plugins/controltips/style.css b/client/plugins/controltips/style.css new file mode 100644 index 00000000..0ab48856 --- /dev/null +++ b/client/plugins/controltips/style.css @@ -0,0 +1,33 @@ +#control-tips-panel { + align-self: center; + display: flex; + flex-flow: column wrap; + font-size: 13px; + justify-self: flex-end; + position: absolute; + right: 10px; + row-gap: 20px; + text-align: right; + z-index: 999; +} + +#control-tips-panel>* { + align-items: center; + align-self: end; + background-color: var(--background-steel); + border-radius: var(--border-radius-md); + color: white; + column-gap: 8px; + display: flex; + justify-items: right; + opacity: .9; + padding: 5px; + width: fit-content; +} + +#control-tips-panel>*>.key { + background-color: var(--background-grey); + border-radius: var(--border-radius-sm); + color: white; + padding: 1px 4px; +} \ No newline at end of file diff --git a/client/plugins/controltips/tsconfig.json b/client/plugins/controltips/tsconfig.json new file mode 100644 index 00000000..2ba9ed01 --- /dev/null +++ b/client/plugins/controltips/tsconfig.json @@ -0,0 +1,104 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Language and Environment */ + "target": "ES2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + "rootDirs": ["./src", "../../@types"], /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + "typeRoots": [ + "./node_modules/@types", + "../../@types" + ], /* Specify multiple folders that act like './node_modules/@types'. */ + "types": [ + "olympus" + ], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + /* JavaScript Support */ + "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "include": [ + "src/*.ts", + "../../@types/*.d.ts" + ] +} \ No newline at end of file diff --git a/client/public/stylesheets/style/style.css b/client/public/stylesheets/style/style.css index a2b19cc1..cf24f776 100644 --- a/client/public/stylesheets/style/style.css +++ b/client/public/stylesheets/style/style.css @@ -653,17 +653,6 @@ nav.ol-panel> :last-child { stroke: var(--background-steel) !important; } -#atc-navbar-control { - align-items: center; - display: flex; - flex-direction: column; -} - -#atc-navbar-control button svg { - height: 24px; - width: 24px; -} - #roe-buttons-container button, #reaction-to-threat-buttons-container button, #emissions-countermeasures-buttons-container button { diff --git a/client/routes/api/atc.js b/client/routes/api/atc.js index 2429cdce..b0896b15 100644 --- a/client/routes/api/atc.js +++ b/client/routes/api/atc.js @@ -1,82 +1,65 @@ -var express = require('express'); -var app = express(); +var express = require('express'); +var app = express(); const bodyParser = require('body-parser'); -app.use(bodyParser.urlencoded({ extended: false})); +app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); - -/* - - Flight: - "name" - "take-off time" - "priority" - "status" - -//*/ - function uuidv4() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } - - - -function Flight( name, boardId, unitId ) { +function Flight(name, boardId, unitId) { this.assignedAltitude = 0; - this.assignedSpeed = 0; - this.id = uuidv4(); - this.boardId = boardId; - this.name = name; - this.status = "unknown"; - this.takeoffTime = -1; - this.unitId = parseInt( unitId ); + this.assignedSpeed = 0; + this.id = uuidv4(); + this.boardId = boardId; + this.name = name; + this.status = "unknown"; + this.takeoffTime = -1; + this.unitId = parseInt(unitId); } -Flight.prototype.getData = function() { +Flight.prototype.getData = function () { return { - "assignedAltitude" : this.assignedAltitude, - "assignedSpeed" : this.assignedSpeed, - "id" : this.id, - "boardId" : this.boardId, - "name" : this.name, - "status" : this.status, - "takeoffTime" : this.takeoffTime, - "unitId" : this.unitId + "assignedAltitude": this.assignedAltitude, + "assignedSpeed": this.assignedSpeed, + "id": this.id, + "boardId": this.boardId, + "name": this.name, + "status": this.status, + "takeoffTime": this.takeoffTime, + "unitId": this.unitId }; } +Flight.prototype.setAssignedAltitude = function (assignedAltitude) { -Flight.prototype.setAssignedAltitude = function( assignedAltitude ) { - - if ( isNaN( assignedAltitude ) ) { + if (isNaN(assignedAltitude)) { return "Altitude must be a number" } - this.assignedAltitude = parseInt( assignedAltitude ); + this.assignedAltitude = parseInt(assignedAltitude); return true; } +Flight.prototype.setAssignedSpeed = function (assignedSpeed) { -Flight.prototype.setAssignedSpeed = function( assignedSpeed ) { - - if ( isNaN( assignedSpeed ) ) { + if (isNaN(assignedSpeed)) { return "Speed must be a number" } - this.assignedSpeed = parseInt( assignedSpeed ); + this.assignedSpeed = parseInt(assignedSpeed); return true; } - -Flight.prototype.setOrder = function( order ) { +Flight.prototype.setOrder = function (order) { this.order = order; @@ -84,10 +67,9 @@ Flight.prototype.setOrder = function( order ) { } +Flight.prototype.setStatus = function (status) { -Flight.prototype.setStatus = function( status ) { - - if ( [ "unknown", "checkedin", "readytotaxi", "clearedtotaxi", "halted", "terminated" ].indexOf( status ) < 0 ) { + if (["unknown", "checkedin", "readytotaxi", "clearedtotaxi", "halted", "terminated"].indexOf(status) < 0) { return "Invalid status"; } @@ -97,197 +79,186 @@ Flight.prototype.setStatus = function( status ) { } +Flight.prototype.setTakeoffTime = function (takeoffTime) { -Flight.prototype.setTakeoffTime = function( takeoffTime ) { - - if ( takeoffTime === "" || takeoffTime === -1 ) { + if (takeoffTime === "" || takeoffTime === -1) { this.takeoffTime = -1; } - if ( isNaN( takeoffTime ) ) { + if (isNaN(takeoffTime)) { return "Invalid takeoff time" } - this.takeoffTime = parseInt( takeoffTime ); + this.takeoffTime = parseInt(takeoffTime); return true; } - - -function ATCDataHandler( data ) { +function ATCDataHandler(data) { this.data = data; } -ATCDataHandler.prototype.addFlight = function( flight ) { +ATCDataHandler.prototype.addFlight = function (flight) { - if ( flight instanceof Flight === false ) { - throw new Error( "Given flight is not an instance of Flight" ); + if (flight instanceof Flight === false) { + throw new Error("Given flight is not an instance of Flight"); } - this.data.flights[ flight.id ] = flight; + this.data.flights[flight.id] = flight; } - -ATCDataHandler.prototype.deleteFlight = function( flightId ) { - delete this.data.flights[ flightId ]; +ATCDataHandler.prototype.deleteFlight = function (flightId) { + delete this.data.flights[flightId]; } - -ATCDataHandler.prototype.getFlight = function( flightId ) { - return this.data.flights[ flightId ] || false; +ATCDataHandler.prototype.getFlight = function (flightId) { + return this.data.flights[flightId] || false; } - -ATCDataHandler.prototype.getFlights = function() { +ATCDataHandler.prototype.getFlights = function () { return this.data.flights; } - -const dataHandler = new ATCDataHandler( { +const dataHandler = new ATCDataHandler({ "flights": {} -} ); - - +}); /**************************************************************************************************************/ // Endpoints /**************************************************************************************************************/ +app.get("/flight", (req, res) => { + let flights = Object.values(dataHandler.getFlights()); -app.get( "/flight", ( req, res ) => { + if (flights && req.query.boardId) { - let flights = Object.values( dataHandler.getFlights() ); - - if ( flights && req.query.boardId ) { - - flights = flights.reduce( ( acc, flight ) => { - if ( flight.boardId === req.query.boardId ) { - acc[ flight.id ] = flight; + flights = flights.reduce((acc, flight) => { + if (flight.boardId === req.query.boardId) { + acc[flight.id] = flight; } return acc; - }, {} ); + }, {}); } - res.json( flights ); + res.json(flights); }); -app.patch( "/flight/:flightId", ( req, res ) => { +app.patch("/flight/:flightId", (req, res) => { const flightId = req.params.flightId; - const flight = dataHandler.getFlight( flightId ); + const flight = dataHandler.getFlight(flightId); - if ( !flight ) { - res.status( 400 ).send( `Unrecognised flight ID (given: "${req.params.flightId}")` ); + if (!flight) { + res.status(400).send(`Unrecognised flight ID (given: "${req.params.flightId}")`); } - if ( req.body.hasOwnProperty( "assignedAltitude" ) ) { + if (req.body.hasOwnProperty("assignedAltitude")) { - const altitudeChangeSuccess = flight.setAssignedAltitude( req.body.assignedAltitude ); + const altitudeChangeSuccess = flight.setAssignedAltitude(req.body.assignedAltitude); - if ( altitudeChangeSuccess !== true ) { - res.status( 400 ).send( altitudeChangeSuccess ); + if (altitudeChangeSuccess !== true) { + res.status(400).send(altitudeChangeSuccess); } } - if ( req.body.hasOwnProperty( "assignedSpeed" ) ) { + if (req.body.hasOwnProperty("assignedSpeed")) { - const speedChangeSuccess = flight.setAssignedSpeed( req.body.assignedSpeed ); + const speedChangeSuccess = flight.setAssignedSpeed(req.body.assignedSpeed); - if ( speedChangeSuccess !== true ) { - res.status( 400 ).send( speedChangeSuccess ); + if (speedChangeSuccess !== true) { + res.status(400).send(speedChangeSuccess); } } - if ( req.body.status ) { + if (req.body.status) { - const statusChangeSuccess = flight.setStatus( req.body.status ); + const statusChangeSuccess = flight.setStatus(req.body.status); - if ( statusChangeSuccess !== true ) { - res.status( 400 ).send( statusChangeSuccess ); + if (statusChangeSuccess !== true) { + res.status(400).send(statusChangeSuccess); } } - if ( req.body.hasOwnProperty( "takeoffTime" ) ) { + if (req.body.hasOwnProperty("takeoffTime")) { - const takeoffChangeSuccess = flight.setTakeoffTime( req.body.takeoffTime ); + const takeoffChangeSuccess = flight.setTakeoffTime(req.body.takeoffTime); - if ( takeoffChangeSuccess !== true ) { - res.status( 400 ).send( takeoffChangeSuccess ); + if (takeoffChangeSuccess !== true) { + res.status(400).send(takeoffChangeSuccess); } } - res.json( flight.getData() ); + res.json(flight.getData()); }); -app.post( "/flight/order", ( req, res ) => { +app.post("/flight/order", (req, res) => { - if ( !req.body.boardId ) { - res.status( 400 ).send( "Invalid/missing boardId" ); + if (!req.body.boardId) { + res.status(400).send("Invalid/missing boardId"); } - if ( !req.body.order || !Array.isArray( req.body.order ) ) { - res.status( 400 ).send( "Invalid/missing boardId" ); + if (!req.body.order || !Array.isArray(req.body.order)) { + res.status(400).send("Invalid/missing boardId"); } - req.body.order.forEach( ( flightId, i ) => { + req.body.order.forEach((flightId, i) => { - dataHandler.getFlight( flightId ).setOrder( i ); + dataHandler.getFlight(flightId).setOrder(i); }); - res.send( "" ); + res.send(""); }); -app.post( "/flight", ( req, res ) => { +app.post("/flight", (req, res) => { - if ( !req.body.boardId ) { - res.status( 400 ).send( "Invalid/missing boardId" ); + if (!req.body.boardId) { + res.status(400).send("Invalid/missing boardId"); } - if ( !req.body.name ) { - res.status( 400 ).send( "Invalid/missing flight name" ); + if (!req.body.name) { + res.status(400).send("Invalid/missing flight name"); } - if ( !req.body.unitId || isNaN( req.body.unitId ) ) { - res.status( 400 ).send( "Invalid/missing unitId" ); + if (!req.body.unitId || isNaN(req.body.unitId)) { + res.status(400).send("Invalid/missing unitId"); } - const flight = new Flight( req.body.name, req.body.boardId, req.body.unitId ); + const flight = new Flight(req.body.name, req.body.boardId, req.body.unitId); - dataHandler.addFlight( flight ); + dataHandler.addFlight(flight); - res.status( 201 ); + res.status(201); - res.json( flight.getData() ); + res.json(flight.getData()); }); -app.delete( "/flight/:flightId", ( req, res ) => { +app.delete("/flight/:flightId", (req, res) => { - const flight = dataHandler.getFlight( req.params.flightId ); + const flight = dataHandler.getFlight(req.params.flightId); - if ( !flight ) { - res.status( 400 ).send( `Unrecognised flight ID (given: "${req.params.flightId}")` ); + if (!flight) { + res.status(400).send(`Unrecognised flight ID (given: "${req.params.flightId}")`); } - dataHandler.deleteFlight( req.params.flightId ); + dataHandler.deleteFlight(req.params.flightId); - res.status( 204 ).send( "" ); + res.status(204).send(""); }); diff --git a/client/routes/plugins.js b/client/routes/plugins.js new file mode 100644 index 00000000..1ed9511f --- /dev/null +++ b/client/routes/plugins.js @@ -0,0 +1,23 @@ +const express = require('express'); +const fs = require('fs'); +const path = require('path'); + +const pluginsDirectory = "./public/plugins" + +const router = express.Router(); + +function listDirectories(source) { + const directories = fs.readdirSync(source, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .map(dirent => dirent.name); + + return directories; +} + +router.get('/list', function (req, res) { + var directories = listDirectories(pluginsDirectory); + console.log(directories) + res.send(directories.filter(directory => fs.existsSync(path.join(pluginsDirectory, directory)))); +}); + +module.exports = router; diff --git a/client/routes/resources.js b/client/routes/resources.js index 2be3af2f..308243bc 100644 --- a/client/routes/resources.js +++ b/client/routes/resources.js @@ -1,6 +1,7 @@ const express = require('express'); const router = express.Router(); +// TODO should be user selectable or at least configurable from configuration file var theme = "olympus"; router.get('/theme/*', function (req, res, next) { diff --git a/client/src/@types/server.d.ts b/client/src/@types/server.d.ts deleted file mode 100644 index 851bfd53..00000000 --- a/client/src/@types/server.d.ts +++ /dev/null @@ -1,52 +0,0 @@ -interface AirbasesData { - airbases: {[key: string]: any}, - sessionHash: string; - time: number; -} - -interface BullseyesData { - bullseyes: {[key: string]: {latitude: number, longitude: number, coalition: string}}, - sessionHash: string; - time: number; -} - -interface MissionData { - mission: { - theatre: string, - dateAndTime: DateAndTime; - commandModeOptions: CommandModeOptions; - coalitions: {red: string[], blue: string[]} = {}; - } - time: number; - sessionHash: string; -} - -interface CommandModeOptions { - commandMode: string; - restrictSpawns: boolean; - restrictToCoalition: boolean; - setupTime: number; - spawnPoints: { - red: number, - blue: number - }, - eras: string[] -} - -interface DateAndTime { - date: {Year: number, Month: number, Day: number}; - time: {h: number, m: number, s: number}; - elapsedTime: number; - startTime: number; -} - -interface LogData { - logs: {[key: string]: string}, - sessionHash: string; - time: number; -} - -interface ServerRequestOptions { - time?: number; - commandHash?: string; -} \ No newline at end of file diff --git a/client/src/@types/unit.d.ts b/client/src/@types/unit.d.ts deleted file mode 100644 index 90c7266c..00000000 --- a/client/src/@types/unit.d.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { LatLng } from "leaflet" - -interface UnitSpawnTable { - unitType: string, - location: latlng, - altitude?: number, - loadout?: string, - liveryID: string -} - -interface ObjectIconOptions { - showState: boolean, - showVvi: boolean, - showHotgroup: boolean, - showUnitIcon: boolean, - showShortLabel: boolean, - showFuel: boolean, - showAmmo: boolean, - showSummary: boolean, - showCallsign: boolean, - rotateToHeading: boolean -} - -interface GeneralSettings { - prohibitJettison: boolean; - prohibitAA: boolean; - prohibitAG: boolean; - prohibitAfterburner: boolean; - prohibitAirWpn: boolean; -} - -interface TACAN { - isOn: boolean; - channel: number; - XY: string; - callsign: string; -} - -interface Radio { - frequency: number; - callsign: number; - callsignNumber: number; -} - -interface Ammo { - quantity: number, - name: string, - guidance: number, - category: number, - missileCategory: number -} - -interface Contact { - ID: number, - detectionMethod: number -} - -interface Offset { - x: number, - y: number, - z: number -} - -interface UnitData { - category: string, - ID: number; - alive: boolean; - human: boolean; - controlled: boolean; - coalition: string; - country: number; - name: string; - unitName: string; - groupName: string; - state: string; - task: string; - hasTask: boolean; - position: LatLng; - speed: number; - heading: number; - isTanker: boolean; - isAWACS: boolean; - onOff: boolean; - followRoads: boolean; - fuel: number; - desiredSpeed: number; - desiredSpeedType: string; - desiredAltitude: number; - desiredAltitudeType: string; - leaderID: number; - formationOffset: Offset; - targetID: number; - targetPosition: LatLng; - ROE: string; - reactionToThreat: string; - emissionsCountermeasures: string; - TACAN: TACAN; - radio: Radio; - generalSettings: GeneralSettings; - ammo: Ammo[]; - contacts: Contact[]; - activePath: LatLng[]; - isLeader: boolean; -} \ No newline at end of file diff --git a/client/src/@types/unitdatabase.d.ts b/client/src/@types/unitdatabase.d.ts deleted file mode 100644 index 08c9efbd..00000000 --- a/client/src/@types/unitdatabase.d.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { LatLng } from "leaflet"; -import { Airbase } from "../mission/airbase"; - -interface LoadoutItemBlueprint { - name: string; - quantity: number; - effectiveAgainst?: string; -} - -interface LoadoutBlueprint { - fuel: number; - items: LoadoutItemBlueprint[]; - roles: string[]; - code: string; - name: string; -} - -interface UnitBlueprint { - name: string; - coalition: string; - era: string; - label: string; - shortLabel: string; - type?: string; - range?: string; - loadouts?: LoadoutBlueprint[]; - filename?: string; - liveries?: {[key: string]: {name: string, countries: string[]}}; - cost?: number; -} - -interface UnitSpawnOptions { - roleType: string; - name: string; - latlng: LatLng; - coalition: string; - count: number; - country: string; - loadout: LoadoutBlueprint | undefined; - airbase: Airbase | undefined; - liveryID: string | undefined; - altitude: number | undefined; -} diff --git a/client/src/app.ts b/client/src/app.ts new file mode 100644 index 00000000..749fde68 --- /dev/null +++ b/client/src/app.ts @@ -0,0 +1,290 @@ +import { Map } from "./map/map"; +import { MissionManager } from "./mission/missionmanager"; +import { ConnectionStatusPanel } from "./panels/connectionstatuspanel"; +import { HotgroupPanel } from "./panels/hotgrouppanel"; +import { LogPanel } from "./panels/logpanel"; +import { MouseInfoPanel } from "./panels/mouseinfopanel"; +import { ServerStatusPanel } from "./panels/serverstatuspanel"; +import { UnitControlPanel } from "./panels/unitcontrolpanel"; +import { UnitInfoPanel } from "./panels/unitinfopanel"; +import { PluginsManager } from "./plugin/pluginmanager"; +import { Popup } from "./popups/popup"; +import { ShortcutManager } from "./shortcut/shortcutmanager"; +import { CommandModeToolbar } from "./toolbars/commandmodetoolbar"; +import { PrimaryToolbar } from "./toolbars/primarytoolbar"; +import { UnitsManager } from "./unit/unitsmanager"; +import { WeaponsManager } from "./weapon/weaponsmanager"; +import { Manager } from "./other/manager"; +import { ShortcutKeyboard } from "./shortcut/shortcut"; +import { SVGInjector } from "@tanem/svg-injector"; +import { ServerManager } from "./server/servermanager"; + +import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "./constants/constants"; + +export class OlympusApp { + /* Global data */ + #activeCoalition: string = "blue"; + + /* Main leaflet map, extended by custom methods */ + #map: Map | null = null; + + /* Managers */ + #serverManager: ServerManager | null = null; + #unitsManager: UnitsManager | null = null; + #weaponsManager: WeaponsManager | null = null; + #missionManager: MissionManager | null = null; + #pluginsManager: PluginsManager | null = null; + #panelsManager: Manager | null = null; + #popupsManager: Manager | null = null; + #toolbarsManager: Manager | null = null; + #shortcutManager: ShortcutManager | null = null; + + /* UI Toolbars */ + #primaryToolbar: PrimaryToolbar | null = null; + #commandModeToolbar: CommandModeToolbar | null = null; + + constructor() { + + } + + // TODO add checks on null + getMap() { + return this.#map as Map; + } + + getServerManager() { + return this.#serverManager as ServerManager; + } + + getPanelsManager() { + return this.#panelsManager as Manager; + } + + getPopupsManager() { + return this.#popupsManager as Manager; + } + + getToolbarsManager() { + return this.#toolbarsManager as Manager; + } + + getShortcutManager() { + return this.#shortcutManager as ShortcutManager; + } + + getUnitsManager() { + return this.#unitsManager as UnitsManager; + } + + getWeaponsManager() { + return this.#weaponsManager as WeaponsManager; + } + + getMissionManager() { + return this.#missionManager as MissionManager; + } + + getPluginsManager() { + return this.#pluginsManager as PluginsManager; + } + + /** Set the active coalition, i.e. the currently controlled coalition. A game master can change the active coalition, while a commander is bound to his/her coalition + * + * @param newActiveCoalition + */ + setActiveCoalition(newActiveCoalition: string) { + if (this.getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER) + this.#activeCoalition = newActiveCoalition; + } + + /** + * + * @returns The active coalition + */ + getActiveCoalition() { + if (this.getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER) + return this.#activeCoalition; + else { + if (this.getMissionManager().getCommandModeOptions().commandMode == BLUE_COMMANDER) + return "blue"; + else if (this.getMissionManager().getCommandModeOptions().commandMode == RED_COMMANDER) + return "red"; + else + return "neutral"; + } + } + + /** Set a message in the login splash screen + * + * @param status The message to show in the login splash screen + */ + setLoginStatus(status: string) { + const el = document.querySelector("#login-status") as HTMLElement; + if (el) + el.dataset["status"] = status; + } + + start() { + /* Initialize base functionalitites */ + this.#map = new Map('map-container'); + + this.#serverManager = new ServerManager(); + this.#unitsManager = new UnitsManager(); + this.#weaponsManager = new WeaponsManager(); + this.#missionManager = new MissionManager(); + + this.#shortcutManager = new ShortcutManager(); + + this.#panelsManager = new Manager(); + this.#popupsManager = new Manager(); + this.#toolbarsManager = new Manager(); + + // Panels + this.getPanelsManager() + .add("connectionStatus", new ConnectionStatusPanel("connection-status-panel")) + .add("hotgroup", new HotgroupPanel("hotgroup-panel")) + .add("mouseInfo", new MouseInfoPanel("mouse-info-panel")) + .add("log", new LogPanel("log-panel")) + .add("serverStatus", new ServerStatusPanel("server-status-panel")) + .add("unitControl", new UnitControlPanel("unit-control-panel")) + .add("unitInfo", new UnitInfoPanel("unit-info-panel")) + + // Popups + this.getPopupsManager().add("infoPopup", new Popup("info-popup")); + + // Toolbars + this.getToolbarsManager().add("primaryToolbar", new PrimaryToolbar("primary-toolbar")) + .add("commandModeToolbar", new PrimaryToolbar("command-mode-toolbar")); + + this.#pluginsManager = new PluginsManager(); + + /* Load the config file from the app server*/ + this.getServerManager().getConfig((config: ConfigurationOptions) => { + if (config && config.address != undefined && config.port != undefined) { + const address = config.address; + const port = config.port; + if (typeof address === 'string' && typeof port == 'number') { + this.getServerManager().setAddress(address == "*" ? window.location.hostname : address, port); + } + } + else { + throw new Error('Could not read configuration file'); + } + }); + + /* Setup all global events */ + this.#setupEvents(); + } + + #setupEvents() { + /* Generic clicks */ + document.addEventListener("click", (ev) => { + if (ev instanceof MouseEvent && ev.target instanceof HTMLElement) { + const target = ev.target; + + if (target.classList.contains("olympus-dialog-close")) { + target.closest("div.olympus-dialog")?.classList.add("hide"); + } + + const triggerElement = target.closest("[data-on-click]"); + + if (triggerElement instanceof HTMLElement) { + const eventName: string = triggerElement.dataset.onClick || ""; + let params = JSON.parse(triggerElement.dataset.onClickParams || "{}"); + params._element = triggerElement; + + if (eventName) { + document.dispatchEvent(new CustomEvent(eventName, { + detail: params + })); + } + } + } + }); + + const shortcutManager = this.getShortcutManager(); + shortcutManager.add("toggleDemo", new ShortcutKeyboard({ + "callback": () => { + this.getServerManager().toggleDemoEnabled(); + }, + "code": "KeyT" + })).add("togglePause", new ShortcutKeyboard({ + "altKey": false, + "callback": () => { + this.getServerManager().setPaused(!this.getServerManager().getPaused()); + }, + "code": "Space", + "ctrlKey": false + })); + + ["KeyW", "KeyA", "KeyS", "KeyD", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].forEach(code => { + shortcutManager.add(`pan${code}keydown`, new ShortcutKeyboard({ + "altKey": false, + "callback": (ev: KeyboardEvent) => { + this.getMap().handleMapPanning(ev); + }, + "code": code, + "ctrlKey": false, + "event": "keydown" + })); + }); + + ["KeyW", "KeyA", "KeyS", "KeyD", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].forEach(code => { + shortcutManager.add(`pan${code}keyup`, new ShortcutKeyboard({ + "callback": (ev: KeyboardEvent) => { + this.getMap().handleMapPanning(ev); + }, + "code": code + })); + }); + + ["Digit1", "Digit2", "Digit3", "Digit4", "Digit5", "Digit6", "Digit7", "Digit8", "Digit9"].forEach(code => { + shortcutManager.add(`hotgroup${code}`, new ShortcutKeyboard({ + "callback": (ev: KeyboardEvent) => { + if (ev.ctrlKey && ev.shiftKey) + this.getUnitsManager().selectedUnitsAddToHotgroup(parseInt(ev.code.substring(5))); + else if (ev.ctrlKey && !ev.shiftKey) + this.getUnitsManager().selectedUnitsSetHotgroup(parseInt(ev.code.substring(5))); + else + this.getUnitsManager().selectUnitsByHotgroup(parseInt(ev.code.substring(5))); + }, + "code": code + })); + }); + + // TODO: move from here in dedicated class + document.addEventListener("closeDialog", (ev: CustomEventInit) => { + ev.detail._element.closest(".ol-dialog").classList.add("hide"); + }); + + /* Try and connect with the Olympus REST server */ + document.addEventListener("tryConnection", () => { + const form = document.querySelector("#splash-content")?.querySelector("#authentication-form"); + const username = (form?.querySelector("#username") as HTMLInputElement).value; + const password = (form?.querySelector("#password") as HTMLInputElement).value; + + /* Update the user credentials */ + this.getServerManager().setCredentials(username, password); + + /* Start periodically requesting updates */ + this.getServerManager().startUpdate(); + + this.setLoginStatus("connecting"); + }) + + /* Reload the page, used to mimic a restart of the app */ + document.addEventListener("reloadPage", () => { + location.reload(); + }) + + /* Inject the svgs with the corresponding svg code. This allows to dynamically manipulate the svg, like changing colors */ + document.querySelectorAll("[inject-svg]").forEach((el: Element) => { + var img = el as HTMLImageElement; + var isLoaded = img.complete; + if (isLoaded) + SVGInjector(img); + else + img.addEventListener("load", () => { SVGInjector(img); }); + }) + } +} \ No newline at end of file diff --git a/client/src/constants/constants.ts b/client/src/constants/constants.ts index d1124434..608dcd73 100644 --- a/client/src/constants/constants.ts +++ b/client/src/constants/constants.ts @@ -106,7 +106,7 @@ export const layers = { urlTemplate: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", maxZoom: 20, minZoom: 1, - attribution: "Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community" + attribution: "Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, GetApp().getMap()ping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community" }, "USGS Topo": { urlTemplate: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}', diff --git a/client/src/contextmenus/airbasecontextmenu.ts b/client/src/contextmenus/airbasecontextmenu.ts index 5215464a..b8fb6209 100644 --- a/client/src/contextmenus/airbasecontextmenu.ts +++ b/client/src/contextmenus/airbasecontextmenu.ts @@ -1,4 +1,4 @@ -import { getMap, getMissionHandler, getUnitsManager, setActiveCoalition } from ".."; +import { getApp } from ".."; import { GAME_MASTER } from "../constants/constants"; import { Airbase } from "../mission/airbase"; import { dataPointMap } from "../other/utils"; @@ -23,7 +23,7 @@ export class AirbaseContextMenu extends ContextMenu { document.addEventListener("contextMenuLandAirbase", (e: any) => { if (this.#airbase) - getUnitsManager().selectedUnitsLandAt(this.#airbase.getLatLng()); + getApp().getUnitsManager().selectedUnitsLandAt(this.#airbase.getLatLng()); this.hide(); }) } @@ -39,8 +39,8 @@ export class AirbaseContextMenu extends ContextMenu { this.#setProperties(this.#airbase.getProperties()); this.#setParkings(this.#airbase.getParkings()); this.#setCoalition(this.#airbase.getCoalition()); - this.#showLandButton(getUnitsManager().getSelectedUnitsCategories().length == 1 && ["Aircraft", "Helicopter"].includes(getUnitsManager().getSelectedUnitsCategories()[0]) && (getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getCoalition()}) === this.#airbase.getCoalition() || this.#airbase.getCoalition() === "neutral")) - this.#showSpawnButton(getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || this.#airbase.getCoalition() == getMissionHandler().getCommandedCoalition()); + this.#showLandButton(getApp().getUnitsManager().getSelectedUnitsCategories().length == 1 && ["Aircraft", "Helicopter"].includes(getApp().getUnitsManager().getSelectedUnitsCategories()[0]) && (getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getCoalition()}) === this.#airbase.getCoalition() || this.#airbase.getCoalition() === "neutral")) + this.#showSpawnButton(getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || this.#airbase.getCoalition() == getApp().getMissionManager().getCommandedCoalition()); this.#setAirbaseData(); this.clip(); @@ -109,8 +109,8 @@ export class AirbaseContextMenu extends ContextMenu { */ #showSpawnMenu() { if (this.#airbase != null) { - setActiveCoalition(this.#airbase.getCoalition()); - getMap().showAirbaseSpawnMenu(this.getX(), this.getY(), this.getLatLng(), this.#airbase); + getApp().setActiveCoalition(this.#airbase.getCoalition()); + getApp().getMap().showAirbaseSpawnMenu(this.getX(), this.getY(), this.getLatLng(), this.#airbase); } } @@ -135,11 +135,11 @@ export class AirbaseContextMenu extends ContextMenu { if ( runways.length === 0 ) { runwaysContainer.innerText = "No data"; } else { - runways.forEach( runway => { + runways.forEach( (runway: AirbaseChartRunwayData) => { let runwayDiv = document.createElement( "div" ); runwayDiv.classList.add( "runway" ); - runway.headings.forEach( headings => { + runway.headings.forEach( (headings: AirbaseChartRunwayHeadingData) => { for ( const [ heading, data ] of Object.entries( headings ) ) { let headingDiv = document.createElement( "div" ); diff --git a/client/src/contextmenus/airbasespawnmenu.ts b/client/src/contextmenus/airbasespawnmenu.ts index 4266a733..a5c40e3c 100644 --- a/client/src/contextmenus/airbasespawnmenu.ts +++ b/client/src/contextmenus/airbasespawnmenu.ts @@ -1,8 +1,8 @@ import { LatLng } from "leaflet"; -import { getActiveCoalition } from ".."; import { ContextMenu } from "./contextmenu"; import { AircraftSpawnMenu, HelicopterSpawnMenu } from "../controls/unitspawnmenu"; import { Airbase } from "../mission/airbase"; +import { getApp } from ".."; /** This context menu is shown when the user wants to spawn a new aircraft or helicopter from the ground at an airbase. * It is shown by clicking on the "spawn" button of a AirbaseContextMenu. */ @@ -54,7 +54,7 @@ export class AirbaseSpawnContextMenu extends ContextMenu { this.#aircraftSpawnMenu.setCountries(); this.#helicopterSpawnMenu.setCountries(); - this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", getActiveCoalition()) }); + this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", getApp().getActiveCoalition()) }); } /** Sets the airbase at which the new unit will be spawned diff --git a/client/src/contextmenus/coalitionareacontextmenu.ts b/client/src/contextmenus/coalitionareacontextmenu.ts index 94a88e36..375355cc 100644 --- a/client/src/contextmenus/coalitionareacontextmenu.ts +++ b/client/src/contextmenus/coalitionareacontextmenu.ts @@ -1,5 +1,5 @@ import { LatLng } from "leaflet"; -import { getMap, getMissionHandler, getUnitsManager } from ".."; +import { getApp } from ".."; import { GAME_MASTER, IADSTypes } from "../constants/constants"; import { CoalitionArea } from "../map/coalitionarea/coalitionarea"; import { ContextMenu } from "./contextmenu"; @@ -54,20 +54,20 @@ export class CoalitionAreaContextMenu extends ContextMenu { document.addEventListener("coalitionAreaBringToBack", (e: any) => { if (this.#coalitionArea) - getMap().bringCoalitionAreaToBack(this.#coalitionArea); - getMap().hideCoalitionAreaContextMenu(); + getApp().getMap().bringCoalitionAreaToBack(this.#coalitionArea); + getApp().getMap().hideCoalitionAreaContextMenu(); }); document.addEventListener("coalitionAreaDelete", (e: any) => { if (this.#coalitionArea) - getMap().deleteCoalitionArea(this.#coalitionArea); - getMap().hideCoalitionAreaContextMenu(); + getApp().getMap().deleteCoalitionArea(this.#coalitionArea); + getApp().getMap().hideCoalitionAreaContextMenu(); }); document.addEventListener("contextMenuCreateIads", (e: any) => { const area = this.getCoalitionArea(); if (area) - getUnitsManager().createIADS(area, getCheckboxOptions(this.#iadsTypesDropdown), getCheckboxOptions(this.#iadsErasDropdown), getCheckboxOptions(this.#iadsRangesDropdown), this.#iadsDensitySlider.getValue(), this.#iadsDistributionSlider.getValue()); + getApp().getUnitsManager().createIADS(area, getCheckboxOptions(this.#iadsTypesDropdown), getCheckboxOptions(this.#iadsErasDropdown), getCheckboxOptions(this.#iadsRangesDropdown), this.#iadsDensitySlider.getValue(), this.#iadsDistributionSlider.getValue()); }) this.hide(); } @@ -97,7 +97,7 @@ export class CoalitionAreaContextMenu extends ContextMenu { return createCheckboxOption(range, `Add ${range} units to the IADS`); })); - if (getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) + if (getApp().getMissionManager().getCommandModeOptions().commandMode !== GAME_MASTER) this.#coalitionSwitch.hide() } @@ -149,7 +149,7 @@ export class CoalitionAreaContextMenu extends ContextMenu { * @param value Switch position (false: blue, true: red) */ #onSwitchClick(value: boolean) { - if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER) { + if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER) { this.getCoalitionArea()?.setCoalition(value ? "red" : "blue"); this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", this.getCoalitionArea()?.getCoalition()) diff --git a/client/src/contextmenus/mapcontextmenu.ts b/client/src/contextmenus/mapcontextmenu.ts index b35c1705..2f3c3689 100644 --- a/client/src/contextmenus/mapcontextmenu.ts +++ b/client/src/contextmenus/mapcontextmenu.ts @@ -1,6 +1,5 @@ import { LatLng } from "leaflet"; -import { getActiveCoalition, getMap, getMissionHandler, setActiveCoalition } from ".."; -import { spawnExplosion, spawnSmoke } from "../server/server"; +import { getApp } from ".."; import { ContextMenu } from "./contextmenu"; import { Switch } from "../controls/switch"; import { GAME_MASTER } from "../constants/constants"; @@ -48,20 +47,20 @@ export class MapContextMenu extends ContextMenu { document.addEventListener("contextMenuDeploySmoke", (e: any) => { this.hide(); - spawnSmoke(e.detail.color, this.getLatLng()); + getApp().getServerManager().spawnSmoke(e.detail.color, this.getLatLng()); var marker = new SmokeMarker(this.getLatLng(), e.detail.color); - marker.addTo(getMap()); + marker.addTo(getApp().getMap()); }); document.addEventListener("contextMenuExplosion", (e: any) => { this.hide(); - spawnExplosion(e.detail.strength, this.getLatLng()); + getApp().getServerManager().spawnExplosion(e.detail.strength, this.getLatLng()); }); document.addEventListener("editCoalitionArea", (e: any) => { this.hide(); if (this.#coalitionArea) { - getMap().deselectAllCoalitionAreas(); + getApp().getMap().deselectAllCoalitionAreas(); this.#coalitionArea.setSelected(true); } }); @@ -103,13 +102,13 @@ export class MapContextMenu extends ContextMenu { this.#navyUnitSpawnMenu.setCountries(); /* Only a Game Master can choose the coalition of a new unit */ - if (getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) + if (getApp().getMissionManager().getCommandModeOptions().commandMode !== GAME_MASTER) this.#coalitionSwitch.hide() - this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", getActiveCoalition()) }); - if (getActiveCoalition() == "blue") + this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", getApp().getActiveCoalition()) }); + if (getApp().getActiveCoalition() == "blue") this.#coalitionSwitch.setValue(false); - else if (getActiveCoalition() == "red") + else if (getApp().getActiveCoalition() == "red") this.#coalitionSwitch.setValue(true); else this.#coalitionSwitch.setValue(undefined); @@ -199,8 +198,8 @@ export class MapContextMenu extends ContextMenu { * @param value Switch position (false: "blue", true: "red") */ #onSwitchClick(value: boolean) { - value ? setActiveCoalition("red") : setActiveCoalition("blue"); - this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", getActiveCoalition()) }); + value ? getApp().setActiveCoalition("red") : getApp().setActiveCoalition("blue"); + this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", getApp().getActiveCoalition()) }); this.#aircraftSpawnMenu.setCountries(); this.#helicopterSpawnMenu.setCountries(); this.#groundUnitSpawnMenu.setCountries(); @@ -212,8 +211,8 @@ export class MapContextMenu extends ContextMenu { */ #onSwitchRightClick() { this.#coalitionSwitch.setValue(undefined); - setActiveCoalition("neutral"); - this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", getActiveCoalition()) }); + getApp().setActiveCoalition("neutral"); + this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", getApp().getActiveCoalition()) }); this.#aircraftSpawnMenu.setCountries(); this.#helicopterSpawnMenu.setCountries(); this.#groundUnitSpawnMenu.setCountries(); diff --git a/client/src/controls/dropdown.ts b/client/src/controls/dropdown.ts index f203691f..c7823856 100644 --- a/client/src/controls/dropdown.ts +++ b/client/src/controls/dropdown.ts @@ -68,6 +68,10 @@ export class Dropdown { return this.#options.children; } + addOptionElement(optionElement: HTMLElement) { + this.#options.appendChild(optionElement); + } + selectText(text: string) { const index = [].slice.call(this.#options.children).findIndex((opt: Element) => opt.querySelector("button")?.innerText === text); if (index > -1) { diff --git a/client/src/controls/unitspawnmenu.ts b/client/src/controls/unitspawnmenu.ts index 083806e7..a2702dd8 100644 --- a/client/src/controls/unitspawnmenu.ts +++ b/client/src/controls/unitspawnmenu.ts @@ -2,16 +2,14 @@ import { LatLng } from "leaflet"; import { Dropdown } from "./dropdown"; import { Slider } from "./slider"; import { UnitDatabase } from "../unit/databases/unitdatabase"; -import { getActiveCoalition, getMap, getMissionHandler, getUnitsManager } from ".."; +import { getApp } from ".."; import { GAME_MASTER } from "../constants/constants"; -import { UnitSpawnOptions } from "../@types/unitdatabase"; import { Airbase } from "../mission/airbase"; import { ftToM } from "../other/utils"; import { aircraftDatabase } from "../unit/databases/aircraftdatabase"; import { helicopterDatabase } from "../unit/databases/helicopterdatabase"; import { groundUnitDatabase } from "../unit/databases/groundunitdatabase"; import { navyUnitDatabase } from "../unit/databases/navyunitdatabase"; -import { UnitSpawnTable } from "../@types/unit"; export class UnitSpawnMenu { #container: HTMLElement; @@ -209,8 +207,8 @@ export class UnitSpawnMenu { } setCountries() { - var coalitions = getMissionHandler().getCoalitions(); - var countries = Object.values(coalitions[getActiveCoalition() as keyof typeof coalitions]); + var coalitions = getApp().getMissionManager().getCoalitions(); + var countries = Object.values(coalitions[getApp().getActiveCoalition() as keyof typeof coalitions]); this.#unitCountryDropdown.setOptionsElements(this.#createCountryButtons(this.#unitCountryDropdown, countries, (country: string) => { this.#setUnitCountry(country) })); if (countries.length > 0 && !countries.includes(this.#spawnOptions.country)) { @@ -377,11 +375,11 @@ export class UnitSpawnMenu { } #computeSpawnPoints() { - if (getMissionHandler() && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) { + if (getApp().getMissionManager() && getApp().getMissionManager().getCommandModeOptions().commandMode !== GAME_MASTER) { var unitCount = parseInt(this.#unitCountDropdown.getValue()); var unitSpawnPoints = unitCount * this.#unitDatabase.getSpawnPointsByLabel(this.#unitLabelDropdown.getValue()); this.#deployUnitButtonEl.dataset.points = `${unitSpawnPoints}`; - this.#deployUnitButtonEl.disabled = unitSpawnPoints >= getMissionHandler().getAvailableSpawnPoints(); + this.#deployUnitButtonEl.disabled = unitSpawnPoints >= getApp().getMissionManager().getAvailableSpawnPoints(); } } } @@ -400,7 +398,7 @@ export class AircraftSpawnMenu extends UnitSpawnMenu { } deployUnits(spawnOptions: UnitSpawnOptions, unitsCount: number) { - spawnOptions.coalition = getActiveCoalition(); + spawnOptions.coalition = getApp().getActiveCoalition(); if (spawnOptions) { var unitTable: UnitSpawnTable = { unitType: spawnOptions.name, @@ -414,9 +412,9 @@ export class AircraftSpawnMenu extends UnitSpawnMenu { units.push(unitTable); } - getUnitsManager().spawnUnits("Aircraft", units, getActiveCoalition(), false, spawnOptions.airbase ? spawnOptions.airbase.getName() : "", spawnOptions.country, (res: any) => { + getApp().getUnitsManager().spawnUnits("Aircraft", units, getApp().getActiveCoalition(), false, spawnOptions.airbase ? spawnOptions.airbase.getName() : "", spawnOptions.country, (res: any) => { if (res.commandHash !== undefined) - getMap().addTemporaryMarker(spawnOptions.latlng, spawnOptions.name, getActiveCoalition(), res.commandHash); + getApp().getMap().addTemporaryMarker(spawnOptions.latlng, spawnOptions.name, getApp().getActiveCoalition(), res.commandHash); }); this.getContainer().dispatchEvent(new Event("hide")); @@ -438,7 +436,7 @@ export class HelicopterSpawnMenu extends UnitSpawnMenu { } deployUnits(spawnOptions: UnitSpawnOptions, unitsCount: number) { - spawnOptions.coalition = getActiveCoalition(); + spawnOptions.coalition = getApp().getActiveCoalition(); if (spawnOptions) { var unitTable: UnitSpawnTable = { unitType: spawnOptions.name, @@ -452,9 +450,9 @@ export class HelicopterSpawnMenu extends UnitSpawnMenu { units.push(unitTable); } - getUnitsManager().spawnUnits("Helicopter", units, getActiveCoalition(), false, spawnOptions.airbase ? spawnOptions.airbase.getName() : "", spawnOptions.country, (res: any) => { + getApp().getUnitsManager().spawnUnits("Helicopter", units, getApp().getActiveCoalition(), false, spawnOptions.airbase ? spawnOptions.airbase.getName() : "", spawnOptions.country, (res: any) => { if (res.commandHash !== undefined) - getMap().addTemporaryMarker(spawnOptions.latlng, spawnOptions.name, getActiveCoalition(), res.commandHash); + getApp().getMap().addTemporaryMarker(spawnOptions.latlng, spawnOptions.name, getApp().getActiveCoalition(), res.commandHash); }); this.getContainer().dispatchEvent(new Event("hide")); @@ -476,7 +474,7 @@ export class GroundUnitSpawnMenu extends UnitSpawnMenu { } deployUnits(spawnOptions: UnitSpawnOptions, unitsCount: number) { - spawnOptions.coalition = getActiveCoalition(); + spawnOptions.coalition = getApp().getActiveCoalition(); if (spawnOptions) { var unitTable: UnitSpawnTable = { unitType: spawnOptions.name, @@ -490,9 +488,9 @@ export class GroundUnitSpawnMenu extends UnitSpawnMenu { unitTable.location.lat += i > 0? 0.0001: 0; } - getUnitsManager().spawnUnits("GroundUnit", units, getActiveCoalition(), false, spawnOptions.airbase ? spawnOptions.airbase.getName() : "", spawnOptions.country, (res: any) => { + getApp().getUnitsManager().spawnUnits("GroundUnit", units, getApp().getActiveCoalition(), false, spawnOptions.airbase ? spawnOptions.airbase.getName() : "", spawnOptions.country, (res: any) => { if (res.commandHash !== undefined) - getMap().addTemporaryMarker(spawnOptions.latlng, spawnOptions.name, getActiveCoalition(), res.commandHash); + getApp().getMap().addTemporaryMarker(spawnOptions.latlng, spawnOptions.name, getApp().getActiveCoalition(), res.commandHash); }); this.getContainer().dispatchEvent(new Event("hide")); @@ -514,7 +512,7 @@ export class NavyUnitSpawnMenu extends UnitSpawnMenu { } deployUnits(spawnOptions: UnitSpawnOptions, unitsCount: number) { - spawnOptions.coalition = getActiveCoalition(); + spawnOptions.coalition = getApp().getActiveCoalition(); if (spawnOptions) { var unitTable: UnitSpawnTable = { unitType: spawnOptions.name, @@ -528,9 +526,9 @@ export class NavyUnitSpawnMenu extends UnitSpawnMenu { unitTable.location.lat += i > 0? 0.0001: 0; } - getUnitsManager().spawnUnits("NavyUnit", units, getActiveCoalition(), false, spawnOptions.airbase ? spawnOptions.airbase.getName() : "", spawnOptions.country, (res: any) => { + getApp().getUnitsManager().spawnUnits("NavyUnit", units, getApp().getActiveCoalition(), false, spawnOptions.airbase ? spawnOptions.airbase.getName() : "", spawnOptions.country, (res: any) => { if (res.commandHash !== undefined) - getMap().addTemporaryMarker(spawnOptions.latlng, spawnOptions.name, getActiveCoalition(), res.commandHash); + getApp().getMap().addTemporaryMarker(spawnOptions.latlng, spawnOptions.name, getApp().getActiveCoalition(), res.commandHash); }); this.getContainer().dispatchEvent(new Event("hide")); diff --git a/client/src/features/featureswitches.ts b/client/src/features/featureswitches.ts deleted file mode 100644 index a7cf1c30..00000000 --- a/client/src/features/featureswitches.ts +++ /dev/null @@ -1,153 +0,0 @@ -export interface FeatureSwitchInterface { - "defaultEnabled": boolean, // default on/off state (if allowed by forceState) - "forceState": number, // -1 don't force; 0 force off; 1 force on - "label": string, - "name": string, - "onEnabled"?: CallableFunction, - "options"?: object, - "removeArtifactsIfDisabled"?: boolean -} - - -class FeatureSwitch { - - // From config param - defaultEnabled; - forceState = -1; - label; - name; - onEnabled; - removeArtifactsIfDisabled = true; - - // Self-set - userPreference; - - - constructor(config: FeatureSwitchInterface) { - - this.defaultEnabled = config.defaultEnabled; - this.forceState = config.forceState; - this.label = config.label; - this.name = config.name; - this.onEnabled = config.onEnabled; - - this.userPreference = this.getUserPreference(); - - } - - - getUserPreference() { - - let preferences = JSON.parse(localStorage.getItem("featureSwitches") || "{}"); - - return (preferences.hasOwnProperty(this.name)) ? preferences[this.name] : this.defaultEnabled; - - } - - - isEnabled() { - - if ( this.forceState === 0 ) { - return false; - } - - if ( this.forceState === 1 ) { - return true; - } - - return this.userPreference; - } - -} - -export class FeatureSwitches { - - #featureSwitches: FeatureSwitch[] = [ - - new FeatureSwitch({ - "defaultEnabled": false, - "forceState": -1, - "label": "AIC", - "name": "aic" - }), - - new FeatureSwitch({ - "defaultEnabled": false, - "forceState": -1, - "label": "AI Formations", - "name": "ai-formations", - "removeArtifactsIfDisabled": false - }), - - new FeatureSwitch({ - "defaultEnabled": false, - "forceState": 1, - "label": "ATC", - "name": "atc" - }), - - new FeatureSwitch({ - "defaultEnabled": false, - "forceState": -1, - "label": "Force show unit control panel", - "name": "forceShowUnitControlPanel" - }), - - new FeatureSwitch({ - "defaultEnabled": true, - "forceState": -1, - "label": "Show splash screen", - "name": "splashScreen" - }) - - ]; - - - constructor() { - - this.#testSwitches(); - - this.savePreferences(); - - } - - - getSwitch(switchName: string) { - - return this.#featureSwitches.find(featureSwitch => featureSwitch.name === switchName); - - } - - - #testSwitches() { - for (const featureSwitch of this.#featureSwitches) { - if (featureSwitch.isEnabled()) { - if (typeof featureSwitch.onEnabled === "function") { - featureSwitch.onEnabled(); - } - } else { - document.querySelectorAll("[data-feature-switch='" + featureSwitch.name + "']").forEach(el => { - if (featureSwitch.removeArtifactsIfDisabled === false) { - el.remove(); - } else { - el.classList.add("hide"); - } - }); - } - document.body.classList.toggle("feature-" + featureSwitch.name, featureSwitch.isEnabled()); - } - } - - savePreferences() { - - let preferences: any = {}; - - for (const featureSwitch of this.#featureSwitches) { - preferences[featureSwitch.name] = featureSwitch.isEnabled(); - } - - localStorage.setItem("featureSwitches", JSON.stringify(preferences)); - - } - -} \ No newline at end of file diff --git a/client/src/features/toggleablefeature.ts b/client/src/features/toggleablefeature.ts deleted file mode 100644 index 09f1723e..00000000 --- a/client/src/features/toggleablefeature.ts +++ /dev/null @@ -1,35 +0,0 @@ -export abstract class ToggleableFeature { - - #status: boolean = false; - - - constructor(defaultStatus: boolean) { - - this.#status = defaultStatus; - - this.onStatusUpdate(); - - } - - - getStatus(): boolean { - return this.#status; - } - - - protected onStatusUpdate() { } - - - toggleStatus(force?: boolean): void { - - if (force) { - this.#status = force; - } else { - this.#status = !this.#status; - } - - this.onStatusUpdate(); - - } - -} \ No newline at end of file diff --git a/client/src/index.ts b/client/src/index.ts index 76b52e87..2b637448 100644 --- a/client/src/index.ts +++ b/client/src/index.ts @@ -1,292 +1,14 @@ -import { Map } from "./map/map" -import { UnitsManager } from "./unit/unitsmanager"; -import { UnitInfoPanel } from "./panels/unitinfopanel"; -import { ConnectionStatusPanel } from "./panels/connectionstatuspanel"; -import { MissionManager } from "./mission/missionmanager"; -import { UnitControlPanel } from "./panels/unitcontrolpanel"; -import { MouseInfoPanel } from "./panels/mouseinfopanel"; -import { LogPanel } from "./panels/logpanel"; -import { getConfig, getPaused, setAddress, setCredentials, setPaused, startUpdate, toggleDemoEnabled } from "./server/server"; -import { keyEventWasInInput } from "./other/utils"; -import { Popup } from "./popups/popup"; -import { HotgroupPanel } from "./panels/hotgrouppanel"; -import { SVGInjector } from "@tanem/svg-injector"; -import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "./constants/constants"; -import { ServerStatusPanel } from "./panels/serverstatuspanel"; -import { WeaponsManager } from "./weapon/weaponsmanager"; -import { ConfigParameters } from "./@types/dom"; -import { CommandModeToolbar } from "./toolbars/commandmodetoolbar"; -import { PrimaryToolbar } from "./toolbars/primarytoolbar"; +import { OlympusApp } from "./app"; -/* Global data */ -var activeCoalition: string = "blue"; - -/* Main leaflet map, extended by custom methods */ -var map: Map; - -/* Managers */ -var unitsManager: UnitsManager; -var weaponsManager: WeaponsManager; -var missionManager: MissionManager; - -/* UI Panels */ -var unitInfoPanel: UnitInfoPanel; -var connectionStatusPanel: ConnectionStatusPanel; -var serverStatusPanel: ServerStatusPanel; -var unitControlPanel: UnitControlPanel; -var mouseInfoPanel: MouseInfoPanel; -var logPanel: LogPanel; -var hotgroupPanel: HotgroupPanel; - -/* UI Toolbars */ -var primaryToolbar: PrimaryToolbar; -var commandModeToolbar: CommandModeToolbar; - -/* Popups */ -var infoPopup: Popup; +var app: OlympusApp; function setup() { - - /* Initialize base functionalitites */ - map = new Map('map-container'); - - unitsManager = new UnitsManager(); - weaponsManager = new WeaponsManager(); - missionManager = new MissionManager(); - - /* Panels */ - unitInfoPanel = new UnitInfoPanel("unit-info-panel"); - unitControlPanel = new UnitControlPanel("unit-control-panel"); - connectionStatusPanel = new ConnectionStatusPanel("connection-status-panel"); - serverStatusPanel = new ServerStatusPanel("server-status-panel"); - mouseInfoPanel = new MouseInfoPanel("mouse-info-panel"); - hotgroupPanel = new HotgroupPanel("hotgroup-panel"); - logPanel = new LogPanel("log-panel"); - - /* Toolbars */ - primaryToolbar = new PrimaryToolbar("primary-toolbar"); - commandModeToolbar = new CommandModeToolbar("command-mode-toolbar"); - - /* Popups */ - infoPopup = new Popup("info-popup"); - - /* Setup event handlers */ - setupEvents(); - - /* Load the config file from the app server*/ - getConfig((config: ConfigParameters) => readConfig(config)); + app = new OlympusApp(); + app.start(); } -/** Loads the configuration parameters - * - * @param config ConfigParameters, defines the address and port of the Olympus REST server - */ -function readConfig(config: ConfigParameters) { - if (config && config.address != undefined && config.port != undefined) { - const address = config.address; - const port = config.port; - if (typeof address === 'string' && typeof port == 'number') - setAddress(address == "*" ? window.location.hostname : address, port); - } - else { - throw new Error('Could not read configuration file'); - } +export function getApp() { + return app; } - -/** Setup the global window events - * - */ -function setupEvents() { - /* Generic clicks. The "data-on-click" html parameter is used to call a generic callback from the html code. - It is used by all the statically defined elements of the UI. Dynamically generated elements should directly generate the events instead. - */ - document.addEventListener("click", (ev) => { - if (ev instanceof MouseEvent && ev.target instanceof HTMLElement) { - const target = ev.target; - - if (target.classList.contains("olympus-dialog-close")) { - target.closest("div.olympus-dialog")?.classList.add("hide"); - } - - const triggerElement = target.closest("[data-on-click]"); - - if (triggerElement instanceof HTMLElement) { - const eventName: string = triggerElement.dataset.onClick || ""; - let params = JSON.parse(triggerElement.dataset.onClickParams || "{}"); - params._element = triggerElement; - - if (eventName) { - document.dispatchEvent(new CustomEvent(eventName, { - detail: params - })); - } - } - } - }); - - /* Keyup events */ - document.addEventListener("keyup", ev => { - if (keyEventWasInInput(ev)) { - return; - } - switch (ev.code) { - case "KeyT": - toggleDemoEnabled(); - break; - case "Space": - setPaused(!getPaused()); - break; - case "KeyW": case "KeyA": case "KeyS": case "KeyD": - case "ArrowLeft": case "ArrowRight": case "ArrowUp": case "ArrowDown": - getMap().handleMapPanning(ev); - break; - case "Digit1": case "Digit2": case "Digit3": case "Digit4": case "Digit5": case "Digit6": case "Digit7": case "Digit8": case "Digit9": - /* Using the substring because the key will be invalid when pressing the Shift key */ - if (ev.ctrlKey && ev.shiftKey) - getUnitsManager().selectedUnitsAddToHotgroup(parseInt(ev.code.substring(5))); - else if (ev.ctrlKey && !ev.shiftKey) - getUnitsManager().selectedUnitsSetHotgroup(parseInt(ev.code.substring(5))); - else - getUnitsManager().selectUnitsByHotgroup(parseInt(ev.code.substring(5))); - break; - } - }); - - /* Keydown events */ - document.addEventListener("keydown", ev => { - if (keyEventWasInInput(ev)) { - return; - } - switch (ev.code) { - case "KeyW": case "KeyA": case "KeyS": case "KeyD": case "ArrowLeft": case "ArrowRight": case "ArrowUp": case "ArrowDown": - getMap().handleMapPanning(ev); - break; - } - }); - - // TODO: move from here in dedicated class - document.addEventListener("closeDialog", (ev: CustomEventInit) => { - ev.detail._element.closest(".ol-dialog").classList.add("hide"); - }); - - /* Try and connect with the Olympus REST server */ - document.addEventListener("tryConnection", () => { - const form = document.querySelector("#splash-content")?.querySelector("#authentication-form"); - const username = (form?.querySelector("#username") as HTMLInputElement).value; - const password = (form?.querySelector("#password") as HTMLInputElement).value; - - /* Update the user credentials */ - setCredentials(username, password); - - /* Start periodically requesting updates */ - startUpdate(); - - setLoginStatus("connecting"); - }) - - /* Reload the page, used to mimic a restart of the app */ - document.addEventListener("reloadPage", () => { - location.reload(); - }) - - /* Inject the svgs with the corresponding svg code. This allows to dynamically manipulate the svg, like changing colors */ - document.querySelectorAll("[inject-svg]").forEach((el: Element) => { - var img = el as HTMLImageElement; - var isLoaded = img.complete; - if (isLoaded) - SVGInjector(img); - else - img.addEventListener("load", () => { - SVGInjector(img); - }); - }) -} - -/* Getters */ -export function getMap() { - return map; -} - -export function getUnitsManager() { - return unitsManager; -} - -export function getWeaponsManager() { - return weaponsManager; -} - -export function getMissionHandler() { - return missionManager; -} - -export function getUnitInfoPanel() { - return unitInfoPanel; -} - -export function getUnitControlPanel() { - return unitControlPanel; -} - -export function getMouseInfoPanel() { - return mouseInfoPanel; -} - -export function getLogPanel() { - return logPanel; -} - -export function getConnectionStatusPanel() { - return connectionStatusPanel; -} - -export function getServerStatusPanel() { - return serverStatusPanel; -} - -export function getHotgroupPanel() { - return hotgroupPanel; -} - -export function getInfoPopup() { - return infoPopup; -} - -/** Set the active coalition, i.e. the currently controlled coalition. A game master can change the active coalition, while a commander is bound to his/her coalition - * - * @param newActiveCoalition - */ -export function setActiveCoalition(newActiveCoalition: string) { - if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER) - activeCoalition = newActiveCoalition; -} - -/** - * - * @returns The active coalition - */ -export function getActiveCoalition() { - if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER) - return activeCoalition; - else { - if (getMissionHandler().getCommandModeOptions().commandMode == BLUE_COMMANDER) - return "blue"; - else if (getMissionHandler().getCommandModeOptions().commandMode == RED_COMMANDER) - return "red"; - else - return "neutral"; - } -} - -/** Set a message in the login splash screen - * - * @param status The message to show in the login splash screen - */ -export function setLoginStatus(status: string) { - const el = document.querySelector("#login-status") as HTMLElement; - if (el) - el.dataset["status"] = status; -} - -window.onload = setup; - +window.onload = setup; \ No newline at end of file diff --git a/client/src/map/coalitionarea/coalitionarea.ts b/client/src/map/coalitionarea/coalitionarea.ts index fb3682c6..e5e71ae0 100644 --- a/client/src/map/coalitionarea/coalitionarea.ts +++ b/client/src/map/coalitionarea/coalitionarea.ts @@ -1,5 +1,5 @@ import { DomUtil, LatLng, LatLngExpression, Map, Point, Polygon, PolylineOptions } from "leaflet"; -import { getMap, getMissionHandler, getUnitsManager } from "../.."; +import { getApp } from "../.."; import { CoalitionAreaHandle } from "./coalitionareahandle"; import { CoalitionAreaMiddleHandle } from "./coalitionareamiddlehandle"; import { BLUE_COMMANDER, RED_COMMANDER } from "../../constants/constants"; @@ -23,8 +23,8 @@ export class CoalitionArea extends Polygon { this.#setColors(); this.#registerCallbacks(); - if ([BLUE_COMMANDER, RED_COMMANDER].includes(getMissionHandler().getCommandModeOptions().commandMode)) - this.setCoalition(getMissionHandler().getCommandedCoalition()); + if ([BLUE_COMMANDER, RED_COMMANDER].includes(getApp().getMissionManager().getCommandModeOptions().commandMode)) + this.setCoalition(getApp().getMissionManager().getCommandedCoalition()); } setCoalition(coalition: string) { @@ -61,7 +61,7 @@ export class CoalitionArea extends Polygon { /* Remove areas with less than 2 vertexes */ if (latlngs.length <= 2) - getMap().deleteCoalitionArea(this); + getApp().getMap().deleteCoalitionArea(this); } getEditing() { @@ -89,7 +89,7 @@ export class CoalitionArea extends Polygon { onRemove(map: Map): this { super.onRemove(map); - this.#handles.concat(this.#middleHandles).forEach((handle: CoalitionAreaHandle | CoalitionAreaMiddleHandle) => handle.removeFrom(getMap())); + this.#handles.concat(this.#middleHandles).forEach((handle: CoalitionAreaHandle | CoalitionAreaMiddleHandle) => handle.removeFrom(getApp().getMap())); return this; } @@ -99,14 +99,14 @@ export class CoalitionArea extends Polygon { } #setHandles() { - this.#handles.forEach((handle: CoalitionAreaHandle) => handle.removeFrom(getMap())); + this.#handles.forEach((handle: CoalitionAreaHandle) => handle.removeFrom(getApp().getMap())); this.#handles = []; if (this.getSelected()) { var latlngs = this.getLatLngs()[0] as LatLng[]; latlngs.forEach((latlng: LatLng, idx: number) => { /* Add the polygon vertex handle (for moving the vertex) */ const handle = new CoalitionAreaHandle(latlng); - handle.addTo(getMap()); + handle.addTo(getApp().getMap()); handle.on("drag", (e: any) => { var latlngs = this.getLatLngs()[0] as LatLng[]; latlngs[idx] = e.target.getLatLng(); @@ -120,7 +120,7 @@ export class CoalitionArea extends Polygon { } #setMiddleHandles() { - this.#middleHandles.forEach((handle: CoalitionAreaMiddleHandle) => handle.removeFrom(getMap())); + this.#middleHandles.forEach((handle: CoalitionAreaMiddleHandle) => handle.removeFrom(getApp().getMap())); this.#middleHandles = []; var latlngs = this.getLatLngs()[0] as LatLng[]; if (this.getSelected() && latlngs.length >= 2) { @@ -128,13 +128,13 @@ export class CoalitionArea extends Polygon { latlngs.concat([latlngs[0]]).forEach((latlng: LatLng, idx: number) => { /* Add the polygon middle point handle (for adding new vertexes) */ if (lastLatLng != null) { - const handle1Point = getMap().latLngToLayerPoint(latlng); - const handle2Point = getMap().latLngToLayerPoint(lastLatLng); + const handle1Point = getApp().getMap().latLngToLayerPoint(latlng); + const handle2Point = getApp().getMap().latLngToLayerPoint(lastLatLng); const middlePoint = new Point((handle1Point.x + handle2Point.x) / 2, (handle1Point.y + handle2Point.y) / 2); - const middleLatLng = getMap().layerPointToLatLng(middlePoint); + const middleLatLng = getApp().getMap().layerPointToLatLng(middlePoint); const middleHandle = new CoalitionAreaMiddleHandle(middleLatLng); - middleHandle.addTo(getMap()); + middleHandle.addTo(getApp().getMap()); middleHandle.on("click", (e: any) => { this.#activeIndex = idx - 1; this.addTemporaryLatLng(middleLatLng); @@ -148,7 +148,7 @@ export class CoalitionArea extends Polygon { #registerCallbacks() { this.on("click", (e: any) => { - getMap().deselectAllCoalitionAreas(); + getApp().getMap().deselectAllCoalitionAreas(); if (!this.getSelected()) { this.setSelected(true); } @@ -156,7 +156,7 @@ export class CoalitionArea extends Polygon { this.on("contextmenu", (e: any) => { if (!this.getEditing()) { - getMap().deselectAllCoalitionAreas(); + getApp().getMap().deselectAllCoalitionAreas(); this.setSelected(true); } else diff --git a/client/src/map/map.ts b/client/src/map/map.ts index 93f86408..479bae5e 100644 --- a/client/src/map/map.ts +++ b/client/src/map/map.ts @@ -1,5 +1,5 @@ import * as L from "leaflet" -import { getInfoPopup, getMissionHandler, getUnitsManager } from ".."; +import { getApp } from ".."; import { BoxSelect } from "./boxselect"; import { MapContextMenu } from "../contextmenus/mapcontextmenu"; import { UnitContextMenu } from "../contextmenus/unitcontextmenu"; @@ -18,10 +18,11 @@ import { CoalitionArea } from "./coalitionarea/coalitionarea"; import { CoalitionAreaContextMenu } from "../contextmenus/coalitionareacontextmenu"; import { DrawingCursor } from "./coalitionarea/drawingcursor"; import { AirbaseSpawnContextMenu } from "../contextmenus/airbasespawnmenu"; +import { Popup } from "../popups/popup"; L.Map.addInitHook('addHandler', 'boxSelect', BoxSelect); -// TODO would be nice to convert to ts +// TODO would be nice to convert to ts - yes require("../../public/javascripts/leaflet.nauticscale.js") require("../../public/javascripts/L.Path.Drag.js") @@ -123,17 +124,17 @@ export class Map extends L.Map { const el = ev.detail._element; el?.classList.toggle("off"); this.setHiddenType(ev.detail.coalition, !el?.classList.contains("off")); - Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility()); + Object.values(getApp().getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility()); }); document.addEventListener("toggleMarkerVisibility", (ev: CustomEventInit) => { const el = ev.detail._element; el?.classList.toggle("off"); ev.detail.types.forEach((type: string) => this.setHiddenType(type, !el?.classList.contains("off"))); - Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility()); + Object.values(getApp().getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility()); if (ev.detail.types.includes("airbase")) { - Object.values(getMissionHandler().getAirbases()).forEach((airbase: Airbase) => { + Object.values(getApp().getMissionManager().getAirbases()).forEach((airbase: Airbase) => { if (el?.classList.contains("off")) airbase.removeFrom(this); else @@ -178,16 +179,16 @@ export class Map extends L.Map { document.querySelector("#unit-visibility-control")?.append(...this.#optionButtons["visibility"]); /* Create the checkboxes to select the advanced visibility options */ - this.#visibilityOptions[SHOW_CONTACT_LINES] = false; - this.#visibilityOptions[HIDE_GROUP_MEMBERS] = true; - this.#visibilityOptions[SHOW_UNIT_PATHS] = true; - this.#visibilityOptions[SHOW_UNIT_TARGETS] = true; - this.#visibilityOptions[SHOW_UNIT_LABELS] = true; - this.#mapVisibilityOptionsDropdown.setOptionsElements(Object.keys(this.#visibilityOptions).map((option: string) => { - return createCheckboxOption(option, option, this.#visibilityOptions[option], (ev: any) => { - this.#setVisibilityOption(option, ev); - }); - })); + this.addVisibilityOption(SHOW_CONTACT_LINES, false); + this.addVisibilityOption(HIDE_GROUP_MEMBERS, true); + this.addVisibilityOption(SHOW_UNIT_PATHS, true); + this.addVisibilityOption(SHOW_UNIT_TARGETS, true); + this.addVisibilityOption(SHOW_UNIT_LABELS, true); + } + + addVisibilityOption(option: string, defaultValue: boolean) { + this.#visibilityOptions[option] = defaultValue; + this.#mapVisibilityOptionsDropdown.addOptionElement(createCheckboxOption(option, option, defaultValue, (ev: any) => { this.#setVisibilityOption(option, ev); })); } setLayer(layerName: string) { @@ -252,7 +253,7 @@ export class Map extends L.Map { else { this.#hiddenTypes.push(key); } - Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility()); + Object.values(getApp().getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility()); } getHiddenTypes() { @@ -359,7 +360,7 @@ export class Map extends L.Map { centerOnUnit(ID: number | null) { if (ID != null) { this.options.scrollWheelZoom = 'center'; - this.#centerUnit = getUnitsManager().getUnitByID(ID); + this.#centerUnit = getApp().getUnitsManager().getUnitByID(ID); } else { this.options.scrollWheelZoom = undefined; @@ -479,7 +480,7 @@ export class Map extends L.Map { } else { this.setState(IDLE); - getUnitsManager().deselectAllUnits(); + getApp().getUnitsManager().deselectAllUnits(); } } } @@ -517,9 +518,9 @@ export class Map extends L.Map { } else if (this.#state === MOVE_UNIT) { if (!e.originalEvent.ctrlKey) { - getUnitsManager().selectedUnitsClearDestinations(); + getApp().getUnitsManager().selectedUnitsClearDestinations(); } - getUnitsManager().selectedUnitsAddDestination(this.#computeDestinationRotation && this.#destinationRotationCenter != null ? this.#destinationRotationCenter : e.latlng, this.#shiftKey, this.#destinationGroupRotation) + getApp().getUnitsManager().selectedUnitsAddDestination(this.#computeDestinationRotation && this.#destinationRotationCenter != null ? this.#destinationRotationCenter : e.latlng, this.#shiftKey, this.#destinationGroupRotation) this.#destinationGroupRotation = 0; this.#destinationRotationCenter = null; @@ -542,7 +543,7 @@ export class Map extends L.Map { this.#leftClickTimer = window.setTimeout(() => { this.#preventLeftClick = false; }, 200); - getUnitsManager().selectFromBounds(e.selectionBounds); + getApp().getUnitsManager().selectFromBounds(e.selectionBounds); this.#updateCursor(); } @@ -567,25 +568,25 @@ export class Map extends L.Map { this.#longPressHandled = true; var options: { [key: string]: { text: string, tooltip: string } } = {}; - const selectedUnits = getUnitsManager().getSelectedUnits(); - const selectedUnitTypes = getUnitsManager().getSelectedUnitsCategories(); + const selectedUnits = getApp().getUnitsManager().getSelectedUnits(); + const selectedUnitTypes = getApp().getUnitsManager().getSelectedUnitsCategories(); if (selectedUnitTypes.length === 1 && ["Aircraft", "Helicopter"].includes(selectedUnitTypes[0])) { if (selectedUnits.every((unit: Unit) => { return unit.canFulfillRole(["CAS", "Strike"]) })) { options["bomb"] = { text: "Precision bombing", tooltip: "Precision bombing of a specific point" }; options["carpet-bomb"] = { text: "Carpet bombing", tooltip: "Carpet bombing close to a point" }; } else { - getInfoPopup().setText(`Selected units can not perform point actions.`); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText(`Selected units can not perform point actions.`); } } else if (selectedUnitTypes.length === 1 && ["GroundUnit", "NavyUnit"].includes(selectedUnitTypes[0])) { if (selectedUnits.every((unit: Unit) => { return ["Gun Artillery", "Rocket Artillery", "Infantry", "IFV", "Tank", "Cruiser", "Destroyer", "Frigate"].includes(unit.getType()) })) options["fire-at-area"] = { text: "Fire at area", tooltip: "Fire at a large area" }; else - getInfoPopup().setText(`Selected units can not perform point actions.`); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText(`Selected units can not perform point actions.`); } else if(selectedUnitTypes.length > 1) { - getInfoPopup().setText(`Multiple unit types selected, no common actions available.`); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText(`Multiple unit types selected, no common actions available.`); } if (Object.keys(options).length > 0) { @@ -593,16 +594,16 @@ export class Map extends L.Map { this.getUnitContextMenu().setOptions(options, (option: string) => { this.hideUnitContextMenu(); if (option === "bomb") { - getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); - getUnitsManager().selectedUnitsBombPoint(this.getMouseCoordinates()); + getApp().getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); + getApp().getUnitsManager().selectedUnitsBombPoint(this.getMouseCoordinates()); } else if (option === "carpet-bomb") { - getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); - getUnitsManager().selectedUnitsCarpetBomb(this.getMouseCoordinates()); + getApp().getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); + getApp().getUnitsManager().selectedUnitsCarpetBomb(this.getMouseCoordinates()); } else if (option === "fire-at-area") { - getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); - getUnitsManager().selectedUnitsFireAtArea(this.getMouseCoordinates()); + getApp().getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); + getApp().getUnitsManager().selectedUnitsFireAtArea(this.getMouseCoordinates()); } }); } @@ -695,7 +696,7 @@ export class Map extends L.Map { #showDestinationCursors() { const singleCursor = !this.#shiftKey; - const selectedUnitsCount = getUnitsManager().getSelectedUnits({ excludeHumans: false, onlyOnePerGroup: true }).length; + const selectedUnitsCount = getApp().getUnitsManager().getSelectedUnits({ excludeHumans: false, onlyOnePerGroup: true }).length; if (selectedUnitsCount > 0) { if (singleCursor && this.#destinationPreviewCursors.length != 1) { this.#hideDestinationCursors(); @@ -725,7 +726,7 @@ export class Map extends L.Map { if (this.#destinationPreviewCursors.length == 1) this.#destinationPreviewCursors[0].setLatLng(this.getMouseCoordinates()); else { - Object.values(getUnitsManager().selectedUnitsComputeGroupDestination(groupLatLng, this.#destinationGroupRotation)).forEach((latlng: L.LatLng, idx: number) => { + Object.values(getApp().getUnitsManager().selectedUnitsComputeGroupDestination(groupLatLng, this.#destinationGroupRotation)).forEach((latlng: L.LatLng, idx: number) => { if (idx < this.#destinationPreviewCursors.length) this.#destinationPreviewCursors[idx].setLatLng(this.#shiftKey ? latlng : this.getMouseCoordinates()); }) diff --git a/client/src/map/markers/smokemarker.ts b/client/src/map/markers/smokemarker.ts index 39cf9f82..d7ec80cf 100644 --- a/client/src/map/markers/smokemarker.ts +++ b/client/src/map/markers/smokemarker.ts @@ -1,7 +1,7 @@ import { DivIcon, LatLngExpression, MarkerOptions } from "leaflet"; import { CustomMarker } from "./custommarker"; import { SVGInjector } from "@tanem/svg-injector"; -import { getMap } from "../.."; +import { getApp } from "../.."; export class SmokeMarker extends CustomMarker { #color: string; @@ -10,7 +10,7 @@ export class SmokeMarker extends CustomMarker { super(latlng, options); this.setZIndexOffset(9999); this.#color = color; - window.setTimeout(() => { this.removeFrom(getMap()); }, 300000) /* Remove the smoke after 5 minutes */ + window.setTimeout(() => { this.removeFrom(getApp().getMap()); }, 300000) /* Remove the smoke after 5 minutes */ } createIcon() { diff --git a/client/src/map/markers/temporaryunitmarker.ts b/client/src/map/markers/temporaryunitmarker.ts index 0f8e55ee..bd538d86 100644 --- a/client/src/map/markers/temporaryunitmarker.ts +++ b/client/src/map/markers/temporaryunitmarker.ts @@ -2,8 +2,7 @@ import { CustomMarker } from "./custommarker"; import { DivIcon, LatLng } from "leaflet"; import { SVGInjector } from "@tanem/svg-injector"; import { getMarkerCategoryByName, getUnitDatabaseByCategory } from "../../other/utils"; -import { isCommandExecuted } from "../../server/server"; -import { getMap } from "../.."; +import { getApp } from "../.."; export class TemporaryUnitMarker extends CustomMarker { #name: string; @@ -25,9 +24,9 @@ export class TemporaryUnitMarker extends CustomMarker { this.#commandHash = commandHash; this.#timer = window.setInterval(() => { if (this.#commandHash !== undefined) { - isCommandExecuted((res: any) => { + getApp().getServerManager().isCommandExecuted((res: any) => { if (res.commandExecuted) { - this.removeFrom(getMap()); + this.removeFrom(getApp().getMap()); window.clearInterval(this.#timer); } }, this.#commandHash) diff --git a/client/src/mission/airbase.ts b/client/src/mission/airbase.ts index 0534803e..dc74fee5 100644 --- a/client/src/mission/airbase.ts +++ b/client/src/mission/airbase.ts @@ -2,30 +2,6 @@ import { DivIcon } from 'leaflet'; import { CustomMarker } from '../map/markers/custommarker'; import { SVGInjector } from '@tanem/svg-injector'; -export interface AirbaseOptions { - name: string, - position: L.LatLng -} - - -export interface AirbaseChartData { - elevation: string, - ICAO: string, - TACAN: string, - runways: AirbaseChartRunwayData[] -} - -export interface AirbaseChartRunwayData { - "headings": AirbaseChartRunwayHeadingData[], - "length": string -} - -export interface AirbaseChartRunwayHeadingData { - [index: string]: { - "magHeading": string, - "ILS": string - } -} export class Airbase extends CustomMarker { #name: string = ""; @@ -66,6 +42,12 @@ export class Airbase extends CustomMarker { img.onload = () => SVGInjector(img); el.appendChild(img); this.getElement()?.appendChild(el); + el.addEventListener( "mouseover", ( ev ) => { + document.dispatchEvent( new CustomEvent( "airbaseMouseover", { detail: this })); + }); + el.addEventListener( "mouseout", ( ev ) => { + document.dispatchEvent( new CustomEvent( "airbaseMouseout", { detail: this })); + }); el.dataset.coalition = this.#coalition; } diff --git a/client/src/mission/missionmanager.ts b/client/src/mission/missionmanager.ts index ffe298ee..5acf3c96 100644 --- a/client/src/mission/missionmanager.ts +++ b/client/src/mission/missionmanager.ts @@ -1,15 +1,15 @@ import { LatLng } from "leaflet"; -import { getInfoPopup, getMap } from ".."; +import { getApp } from ".."; import { Airbase } from "./airbase"; import { Bullseye } from "./bullseye"; import { BLUE_COMMANDER, GAME_MASTER, NONE, RED_COMMANDER } from "../constants/constants"; -import { refreshAll, setCommandModeOptions } from "../server/server"; import { Dropdown } from "../controls/dropdown"; import { groundUnitDatabase } from "../unit/databases/groundunitdatabase"; import { createCheckboxOption, getCheckboxOptions } from "../other/utils"; import { aircraftDatabase } from "../unit/databases/aircraftdatabase"; import { helicopterDatabase } from "../unit/databases/helicopterdatabase"; import { navyUnitDatabase } from "../unit/databases/navyunitdatabase"; +import { Popup } from "../popups/popup"; /** The MissionManager */ export class MissionManager { @@ -29,7 +29,7 @@ export class MissionManager { document.addEventListener("applycommandModeOptions", () => this.#applycommandModeOptions()); /* command-mode settings dialog */ - this.#commandModeDialog = document.querySelector("#command-mode-settings-dialog"); + this.#commandModeDialog = document.querySelector("#command-mode-settings-dialog") as HTMLElement; this.#commandModeErasDropdown = new Dropdown("command-mode-era-options", () => {}); } @@ -38,7 +38,7 @@ export class MissionManager { for (let idx in data.bullseyes) { const bullseye = data.bullseyes[idx]; if (!(idx in this.#bullseyes)) - this.#bullseyes[idx] = new Bullseye([0, 0]).addTo(getMap()); + this.#bullseyes[idx] = new Bullseye([0, 0]).addTo(getApp().getMap()); if (bullseye.latitude && bullseye.longitude && bullseye.coalition) { this.#bullseyes[idx].setLatLng(new LatLng(bullseye.latitude, bullseye.longitude)); @@ -54,7 +54,7 @@ export class MissionManager { this.#airbases[airbase.callsign] = new Airbase({ position: new LatLng(airbase.latitude, airbase.longitude), name: airbase.callsign - }).addTo(getMap()); + }).addTo(getApp().getMap()); this.#airbases[airbase.callsign].on('contextmenu', (e) => this.#onAirbaseClick(e)); this.#loadAirbaseChartData(airbase.callsign); } @@ -72,8 +72,8 @@ export class MissionManager { /* Set the mission theatre */ if (data.mission.theatre != this.#theatre) { this.#theatre = data.mission.theatre; - getMap().setTheatre(this.#theatre); - getInfoPopup().setText("Map set to " + this.#theatre); + getApp().getMap().setTheatre(this.#theatre); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText("Map set to " + this.#theatre); } /* Set the date and time data */ @@ -190,7 +190,7 @@ export class MissionManager { var eras: string[] = []; const enabledEras = getCheckboxOptions(this.#commandModeErasDropdown); Object.keys(enabledEras).forEach((key: string) => {if (enabledEras[key]) eras.push(key)}); - setCommandModeOptions(restrictSpawnsCheckbox.checked, restrictToCoalitionCheckbox.checked, {blue: parseInt(blueSpawnPointsInput.value), red: parseInt(redSpawnPointsInput.value)}, eras, parseInt(setupTimeInput.value) * 60); + getApp().getServerManager().setCommandModeOptions(restrictSpawnsCheckbox.checked, restrictToCoalitionCheckbox.checked, {blue: parseInt(blueSpawnPointsInput.value), red: parseInt(redSpawnPointsInput.value)}, eras, parseInt(setupTimeInput.value) * 60); } #setcommandModeOptions(commandModeOptions: CommandModeOptions) { @@ -228,11 +228,11 @@ export class MissionManager { document.querySelector("#command-mode-settings-button")?.classList.toggle("hide", this.getCommandModeOptions().commandMode !== GAME_MASTER); if (requestRefresh) - refreshAll(); + getApp().getServerManager().refreshAll(); } #onAirbaseClick(e: any) { - getMap().showAirbaseContextMenu(e.originalEvent.x, e.originalEvent.y, e.latlng, e.sourceTarget); + getApp().getMap().showAirbaseContextMenu(e.originalEvent.x, e.originalEvent.y, e.latlng, e.sourceTarget); } #loadAirbaseChartData(callsign: string) { diff --git a/client/src/other/eventsmanager.ts b/client/src/other/eventsmanager.ts new file mode 100644 index 00000000..9173b2b1 --- /dev/null +++ b/client/src/other/eventsmanager.ts @@ -0,0 +1,7 @@ +import { Manager } from "./manager"; + +export abstract class EventsManager extends Manager { + constructor() { + super(); + } +} \ No newline at end of file diff --git a/client/src/other/manager.ts b/client/src/other/manager.ts new file mode 100644 index 00000000..6ac10ea8 --- /dev/null +++ b/client/src/other/manager.ts @@ -0,0 +1,33 @@ +export class Manager { + #items: { [key: string]: any } = {}; + + constructor() { + } + + add(name: string, item: any) { + const regex = new RegExp("^[a-z][a-z0-9]{2,}$", "i"); + if (regex.test(name) === false) { + throw new Error(`Item name "${name}" does not match regex: ${regex.toString()}.`); + } + + if (this.#items.hasOwnProperty(name)) { + throw new Error(`Item with name "${name}" already exists.`); + } + + this.#items[name] = item; + return this; + } + + get(name: string) { + if (this.#items.hasOwnProperty(name)) { + return this.#items[name]; + } else { + return false; + } + } + + getAll() { + return this.#items; + } + +} \ No newline at end of file diff --git a/client/src/other/utils.ts b/client/src/other/utils.ts index 4d46d202..78d025e2 100644 --- a/client/src/other/utils.ts +++ b/client/src/other/utils.ts @@ -7,7 +7,6 @@ import { groundUnitDatabase } from "../unit/databases/groundunitdatabase"; import { Buffer } from "buffer"; import { ROEs, emissionsCountermeasures, reactionsToThreat, states } from "../constants/constants"; import { Dropdown } from "../controls/dropdown"; -import { UnitBlueprint } from "../@types/unitdatabase"; import { navyUnitDatabase } from "../unit/databases/navyunitdatabase"; export function bearing(lat1: number, lon1: number, lat2: number, lon2: number) { diff --git a/client/src/panels/connectionstatuspanel.ts b/client/src/panels/connectionstatuspanel.ts index 6bab6da5..6ab2997e 100644 --- a/client/src/panels/connectionstatuspanel.ts +++ b/client/src/panels/connectionstatuspanel.ts @@ -1,14 +1,11 @@ import { Panel } from "./panel"; export class ConnectionStatusPanel extends Panel { - /** - * - * @param ID - the ID of the HTML element which will contain the context menu - */ - constructor(ID: string){ - super(ID); + constructor(ID: string) { + super( ID ); } + update(connected: boolean) { this.getElement().toggleAttribute( "data-is-connected", connected ); } diff --git a/client/src/panels/hotgrouppanel.ts b/client/src/panels/hotgrouppanel.ts index 94643fa0..007e5b92 100644 --- a/client/src/panels/hotgrouppanel.ts +++ b/client/src/panels/hotgrouppanel.ts @@ -1,4 +1,4 @@ -import { getUnitsManager } from ".."; +import { getApp } from ".."; import { Unit } from "../unit/unit"; import { Panel } from "./panel"; @@ -15,7 +15,7 @@ export class HotgroupPanel extends Panel { refreshHotgroups() { for (let hotgroup = 1; hotgroup <= 9; hotgroup++){ this.removeHotgroup(hotgroup); - if (getUnitsManager().getUnitsByHotgroup(hotgroup).length > 0) + if (getApp().getUnitsManager().getUnitsByHotgroup(hotgroup).length > 0) this.addHotgroup(hotgroup); } @@ -32,7 +32,7 @@ export class HotgroupPanel extends Panel { // Hotgroup unit count var countDiv = document.createElement("div"); - countDiv.innerText = `x${getUnitsManager().getUnitsByHotgroup(hotgroup).length}`; + countDiv.innerText = `x${getApp().getUnitsManager().getUnitsByHotgroup(hotgroup).length}`; var el = document.createElement("div"); el.appendChild(hotgroupDiv); @@ -43,15 +43,15 @@ export class HotgroupPanel extends Panel { this.getElement().appendChild(el); el.addEventListener("click", () => { - getUnitsManager().selectUnitsByHotgroup(hotgroup); + getApp().getUnitsManager().selectUnitsByHotgroup(hotgroup); }); el.addEventListener("mouseover", () => { - getUnitsManager().getUnitsByHotgroup(hotgroup).forEach((unit: Unit) => unit.setHighlighted(true)); + getApp().getUnitsManager().getUnitsByHotgroup(hotgroup).forEach((unit: Unit) => unit.setHighlighted(true)); }); el.addEventListener("mouseout", () => { - getUnitsManager().getUnitsByHotgroup(hotgroup).forEach((unit: Unit) => unit.setHighlighted(false)); + getApp().getUnitsManager().getUnitsByHotgroup(hotgroup).forEach((unit: Unit) => unit.setHighlighted(false)); }); } diff --git a/client/src/panels/logpanel.ts b/client/src/panels/logpanel.ts index a0a38b7c..f41017f2 100644 --- a/client/src/panels/logpanel.ts +++ b/client/src/panels/logpanel.ts @@ -1,4 +1,5 @@ -import { getMouseInfoPanel } from ".."; +import { getApp } from ".."; +import { MouseInfoPanel } from "./mouseinfopanel"; import { Panel } from "./panel"; export class LogPanel extends Panel { @@ -37,7 +38,7 @@ export class LogPanel extends Panel { }); - const mouseInfoPanel = getMouseInfoPanel(); + const mouseInfoPanel = getApp().getPanelsManager().get("mouseInfo") as MouseInfoPanel; new ResizeObserver(() => this.#calculateHeight()).observe(mouseInfoPanel.getElement()) } @@ -89,7 +90,7 @@ export class LogPanel extends Panel { } #calculateHeight() { - const mouseInfoPanel = getMouseInfoPanel(); + const mouseInfoPanel = getApp().getPanelsManager().get("mouseInfo"); if (this.#open) this.getElement().style.height = `${mouseInfoPanel.getElement().offsetTop - this.getElement().offsetTop - 10}px`; else diff --git a/client/src/panels/mouseinfopanel.ts b/client/src/panels/mouseinfopanel.ts index 89a84d26..90ba077c 100644 --- a/client/src/panels/mouseinfopanel.ts +++ b/client/src/panels/mouseinfopanel.ts @@ -1,5 +1,5 @@ import { Icon, LatLng, Marker, Polyline } from "leaflet"; -import { getMap, getMissionHandler, getUnitsManager } from ".."; +import { getApp } from ".."; import { distance, bearing, zeroAppend, mToNm, nmToFt } from "../other/utils"; import { Unit } from "../unit/unit"; import { Panel } from "./panel"; @@ -12,12 +12,8 @@ export class MouseInfoPanel extends Panel { #measureLine: Polyline = new Polyline([], { color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1, interactive: false }); #measureBox: HTMLElement; - /** - * - * @param ID - the ID of the HTML element which will contain the context menu - */ - constructor(ID: string){ - super(ID); + constructor(ID: string) { + super( ID ); this.#measureIcon = new Icon({ iconUrl: 'resources/theme/images/icons/pin.svg', iconAnchor: [16, 32] }); this.#measureMarker = new Marker([0, 0], { icon: this.#measureIcon, interactive: false }); @@ -26,19 +22,19 @@ export class MouseInfoPanel extends Panel { this.#measureBox.classList.add("ol-measure-box", "hide"); document.body.appendChild(this.#measureBox); - getMap()?.on("click", (e: any) => this.#onMapClick(e)); - getMap()?.on('zoom', (e: any) => this.#onZoom(e)); - getMap()?.on('mousemove', (e: any) => this.#onMouseMove(e)); + getApp().getMap()?.on("click", (e: any) => this.#onMapClick(e)); + getApp().getMap()?.on('zoom', (e: any) => this.#onZoom(e)); + getApp().getMap()?.on('mousemove', (e: any) => this.#onMouseMove(e)); document.addEventListener('unitsSelection', (e: CustomEvent) => this.#update()); document.addEventListener('clearSelection', () => this.#update()); } #update() { - const mousePosition = getMap().getMouseCoordinates(); + const mousePosition = getApp().getMap().getMouseCoordinates(); var selectedUnitPosition = null; - var selectedUnits = getUnitsManager().getSelectedUnits(); + var selectedUnits = getApp().getUnitsManager().getSelectedUnits(); if (selectedUnits && selectedUnits.length == 1) selectedUnitPosition = new LatLng(selectedUnits[0].getPosition().lat, selectedUnits[0].getPosition().lng); @@ -48,7 +44,7 @@ export class MouseInfoPanel extends Panel { this.getElement().querySelector(`#measuring-tool`)?.classList.toggle("hide", this.#measurePoint === null && selectedUnitPosition === null); - var bullseyes = getMissionHandler().getBullseyes(); + var bullseyes = getApp().getMissionManager().getBullseyes(); for (let idx in bullseyes) this.#drawMeasure(null, `bullseye-${idx}`, bullseyes[idx].getLatLng(), mousePosition); @@ -65,19 +61,19 @@ export class MouseInfoPanel extends Panel { this.#measureBox.classList.toggle("hide", false); this.#measurePoint = e.latlng; this.#measureMarker.setLatLng(e.latlng); - this.#measureMarker.addTo(getMap()); - if (!getMap().hasLayer(this.#measureLine)) - this.#measureLine.addTo(getMap()); + this.#measureMarker.addTo(getApp().getMap()); + if (!getApp().getMap().hasLayer(this.#measureLine)) + this.#measureLine.addTo(getApp().getMap()); } else { this.#measureBox.classList.toggle("hide", true); this.#measurePoint = null; - if (getMap().hasLayer(this.#measureMarker)) - getMap().removeLayer(this.#measureMarker); + if (getApp().getMap().hasLayer(this.#measureMarker)) + getApp().getMap().removeLayer(this.#measureMarker); this.#measureLine.setLatLngs([]); - if (getMap().hasLayer(this.#measureLine)) - getMap().removeLayer(this.#measureLine); + if (getApp().getMap().hasLayer(this.#measureLine)) + getApp().getMap().removeLayer(this.#measureLine); } } @@ -85,15 +81,15 @@ export class MouseInfoPanel extends Panel { } #drawMeasureLine() { - var mouseLatLng = getMap().containerPointToLatLng(getMap().getMousePosition()); + var mouseLatLng = getApp().getMap().containerPointToLatLng(getApp().getMap().getMousePosition()); if (this.#measurePoint != null) { var points = [this.#measurePoint, mouseLatLng]; this.#measureLine.setLatLngs(points); var dist = distance(this.#measurePoint.lat, this.#measurePoint.lng, mouseLatLng.lat, mouseLatLng.lng); var bear = bearing(this.#measurePoint.lat, this.#measurePoint.lng, mouseLatLng.lat, mouseLatLng.lng); - var startXY = getMap().latLngToContainerPoint(this.#measurePoint); - var dx = (getMap().getMousePosition().x - startXY.x); - var dy = (getMap().getMousePosition().y - startXY.y); + var startXY = getApp().getMap().latLngToContainerPoint(this.#measurePoint); + var dx = (getApp().getMap().getMousePosition().x - startXY.x); + var dy = (getApp().getMap().getMousePosition().y - startXY.y); var angle = Math.atan2(dy, dx); if (angle > Math.PI / 2) @@ -112,8 +108,8 @@ export class MouseInfoPanel extends Panel { let data = [`${bng}°`, `${str} ${unit}`]; this.#measureBox.innerText = data.join(" / "); - this.#measureBox.style.left = (getMap().getMousePosition().x + startXY.x) / 2 - this.#measureBox.offsetWidth / 2 + "px"; - this.#measureBox.style.top = (getMap().getMousePosition().y + startXY.y) / 2 - this.#measureBox.offsetHeight / 2 + "px"; + this.#measureBox.style.left = (getApp().getMap().getMousePosition().x + startXY.x) / 2 - this.#measureBox.offsetWidth / 2 + "px"; + this.#measureBox.style.top = (getApp().getMap().getMousePosition().y + startXY.y) / 2 - this.#measureBox.offsetHeight / 2 + "px"; this.#measureBox.style.rotate = angle + "rad"; } } diff --git a/client/src/panels/panel.ts b/client/src/panels/panel.ts index c4bec3b5..a315ea16 100644 --- a/client/src/panels/panel.ts +++ b/client/src/panels/panel.ts @@ -1,30 +1,31 @@ -export class Panel { - #element: HTMLElement - #visible: boolean = true; +import { PanelEventsManager } from "./paneleventsmanager"; - /** - * - * @param ID - the ID of the HTML element which will contain the context menu - */ - constructor(ID: string){ - this.#element = document.getElementById(ID) as HTMLElement; +export abstract class Panel { + + #element: HTMLElement + #eventsManager!: PanelEventsManager; + + constructor(ID: string) { + this.#element = document.getElementById(ID); + + this.#eventsManager = new PanelEventsManager(); } show() { this.#element.classList.toggle("hide", false); - this.#visible = true; + this.getEventsManager()?.trigger("show", {}); } hide() { this.#element.classList.toggle("hide", true); - this.#visible = false; + this.getEventsManager()?.trigger("hide", {}); } toggle() { // Simple way to track if currently visible - if (this.#visible) + if (this.getVisible()) this.hide(); - else + else this.show(); } @@ -32,7 +33,11 @@ export class Panel { return this.#element; } - getVisible(){ - return this.#visible; + getVisible() { + return (!this.getElement().classList.contains("hide")); + } + + getEventsManager() { + return this.#eventsManager; } } \ No newline at end of file diff --git a/client/src/panels/paneleventsmanager.ts b/client/src/panels/paneleventsmanager.ts new file mode 100644 index 00000000..906f169b --- /dev/null +++ b/client/src/panels/paneleventsmanager.ts @@ -0,0 +1,29 @@ +import { EventsManager } from "../other/eventsmanager"; + +export class PanelEventsManager extends EventsManager { + constructor() { + super(); + + this.add("hide", []); + this.add("show", []); + } + + on(eventName: string, listener: Listener) { + const event = this.get(eventName); + if (!event) { + throw new Error(`Event name "${eventName}" is not valid.`); + } + this.get(eventName).push({ + "callback": listener.callback + }); + } + + trigger(eventName: string, contextData: object) { + const listeners = this.get(eventName); + if (listeners) { + listeners.forEach((listener: Listener) => { + listener.callback(contextData); + }); + } + } +} \ No newline at end of file diff --git a/client/src/panels/serverstatuspanel.ts b/client/src/panels/serverstatuspanel.ts index 64d827b2..74a87a3f 100644 --- a/client/src/panels/serverstatuspanel.ts +++ b/client/src/panels/serverstatuspanel.ts @@ -1,12 +1,8 @@ import { Panel } from "./panel"; export class ServerStatusPanel extends Panel { - /** - * - * @param ID - the ID of the HTML element which will contain the context menu - */ - constructor(ID: string){ - super(ID); + constructor(ID: string) { + super( ID ); } update(frameRate: number, load: number) { diff --git a/client/src/panels/unitcontrolpanel.ts b/client/src/panels/unitcontrolpanel.ts index e8631f1a..24f441b8 100644 --- a/client/src/panels/unitcontrolpanel.ts +++ b/client/src/panels/unitcontrolpanel.ts @@ -1,5 +1,5 @@ import { SVGInjector } from "@tanem/svg-injector"; -import { getUnitsManager } from ".."; +import { getApp } from ".."; import { Dropdown } from "../controls/dropdown"; import { Slider } from "../controls/slider"; import { aircraftDatabase } from "../unit/databases/aircraftdatabase"; @@ -8,7 +8,6 @@ import { Panel } from "./panel"; import { Switch } from "../controls/switch"; import { ROEDescriptions, ROEs, altitudeIncrements, emissionsCountermeasures, emissionsCountermeasuresDescriptions, maxAltitudeValues, maxSpeedValues, minAltitudeValues, minSpeedValues, reactionsToThreat, reactionsToThreatDescriptions, speedIncrements } from "../constants/constants"; import { ftToM, knotsToMs, mToFt, msToKnots } from "../other/utils"; -import { GeneralSettings, Radio, TACAN } from "../@types/unit"; export class UnitControlPanel extends Panel { #altitudeSlider: Slider; @@ -33,24 +32,24 @@ export class UnitControlPanel extends Panel { super(ID); /* Unit control sliders */ - this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => { getUnitsManager().selectedUnitsSetAltitude(ftToM(value)); }); - this.#altitudeTypeSwitch = new Switch("altitude-type-switch", (value: boolean) => { getUnitsManager().selectedUnitsSetAltitudeType(value? "ASL": "AGL"); }); + this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => { getApp().getUnitsManager().selectedUnitsSetAltitude(ftToM(value)); }); + this.#altitudeTypeSwitch = new Switch("altitude-type-switch", (value: boolean) => { getApp().getUnitsManager().selectedUnitsSetAltitudeType(value? "ASL": "AGL"); }); - this.#speedSlider = new Slider("speed-slider", 0, 100, "kts", (value: number) => { getUnitsManager().selectedUnitsSetSpeed(knotsToMs(value)); }); - this.#speedTypeSwitch = new Switch("speed-type-switch", (value: boolean) => { getUnitsManager().selectedUnitsSetSpeedType(value? "CAS": "GS"); }); + this.#speedSlider = new Slider("speed-slider", 0, 100, "kts", (value: number) => { getApp().getUnitsManager().selectedUnitsSetSpeed(knotsToMs(value)); }); + this.#speedTypeSwitch = new Switch("speed-type-switch", (value: boolean) => { getApp().getUnitsManager().selectedUnitsSetSpeedType(value? "CAS": "GS"); }); /* Option buttons */ // Reversing the ROEs so that the least "aggressive" option is always on the left this.#optionButtons["ROE"] = ROEs.slice(0).reverse().map((option: string, index: number) => { - return this.#createOptionButton(option, `roe/${option.toLowerCase()}.svg`, ROEDescriptions.slice(0).reverse()[index], () => { getUnitsManager().selectedUnitsSetROE(option); }); + return this.#createOptionButton(option, `roe/${option.toLowerCase()}.svg`, ROEDescriptions.slice(0).reverse()[index], () => { getApp().getUnitsManager().selectedUnitsSetROE(option); }); }).filter((button: HTMLButtonElement, index: number) => {return ROEs[index] !== "";}); this.#optionButtons["reactionToThreat"] = reactionsToThreat.map((option: string, index: number) => { - return this.#createOptionButton(option, `threat/${option.toLowerCase()}.svg`, reactionsToThreatDescriptions[index],() => { getUnitsManager().selectedUnitsSetReactionToThreat(option); }); + return this.#createOptionButton(option, `threat/${option.toLowerCase()}.svg`, reactionsToThreatDescriptions[index],() => { getApp().getUnitsManager().selectedUnitsSetReactionToThreat(option); }); }); this.#optionButtons["emissionsCountermeasures"] = emissionsCountermeasures.map((option: string, index: number) => { - return this.#createOptionButton(option, `emissions/${option.toLowerCase()}.svg`, emissionsCountermeasuresDescriptions[index],() => { getUnitsManager().selectedUnitsSetEmissionsCountermeasures(option); }); + return this.#createOptionButton(option, `emissions/${option.toLowerCase()}.svg`, emissionsCountermeasuresDescriptions[index],() => { getApp().getUnitsManager().selectedUnitsSetEmissionsCountermeasures(option); }); }); this.getElement().querySelector("#roe-buttons-container")?.append(...this.#optionButtons["ROE"]); @@ -59,12 +58,12 @@ export class UnitControlPanel extends Panel { /* On off switch */ this.#onOffSwitch = new Switch("on-off-switch", (value: boolean) => { - getUnitsManager().selectedUnitsSetOnOff(value); + getApp().getUnitsManager().selectedUnitsSetOnOff(value); }); /* Follow roads switch */ this.#followRoadsSwitch = new Switch("follow-roads-switch", (value: boolean) => { - getUnitsManager().selectedUnitsSetFollowRoads(value); + getApp().getUnitsManager().selectedUnitsSetFollowRoads(value); }); /* Advanced settings dialog */ @@ -84,7 +83,7 @@ export class UnitControlPanel extends Panel { document.addEventListener("clearSelection", () => { this.hide() }); document.addEventListener("applyAdvancedSettings", () => {this.#applyAdvancedSettings();}) document.addEventListener("showAdvancedSettings", () => { - this.#updateAdvancedSettingsDialog(getUnitsManager().getSelectedUnits()); + this.#updateAdvancedSettingsDialog(getApp().getUnitsManager().getSelectedUnits()); this.#advancedSettingsDialog.classList.remove("hide"); }); @@ -108,8 +107,8 @@ export class UnitControlPanel extends Panel { } addButtons() { - this.#units = getUnitsManager().getSelectedUnits(); - this.#selectedUnitsTypes = getUnitsManager().getSelectedUnitsCategories(); + this.#units = getApp().getUnitsManager().getSelectedUnits(); + this.#selectedUnitsTypes = getApp().getUnitsManager().getSelectedUnitsCategories(); if (this.#units.length < 20) { this.getElement().querySelector("#selected-units-container")?.replaceChildren(...this.#units.map((unit: Unit, index: number) => { @@ -127,12 +126,12 @@ export class UnitControlPanel extends Panel { button.addEventListener("click", ( ev:MouseEventInit ) => { // Ctrl-click deselection if ( ev.ctrlKey === true && ev.shiftKey === false && ev.altKey === false ) { - getUnitsManager().deselectUnit( unit.ID ); + getApp().getUnitsManager().deselectUnit( unit.ID ); button.remove(); // Deselect all } else { - getUnitsManager().deselectAllUnits(); - getUnitsManager().selectUnit(unit.ID, true); + getApp().getUnitsManager().deselectAllUnits(); + getApp().getUnitsManager().selectUnit(unit.ID, true); } }); return (button); @@ -161,12 +160,12 @@ export class UnitControlPanel extends Panel { if (this.#selectedUnitsTypes.length == 1) { /* Flight controls */ - var desiredAltitude = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitude()}); - var desiredAltitudeType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitudeType()}); - var desiredSpeed = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeed()}); - var desiredSpeedType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeedType()}); - var onOff = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOnOff()}); - var followRoads = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getFollowRoads()}); + var desiredAltitude = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitude()}); + var desiredAltitudeType = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitudeType()}); + var desiredSpeed = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeed()}); + var desiredSpeedType = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeedType()}); + var onOff = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOnOff()}); + var followRoads = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getFollowRoads()}); this.#altitudeTypeSwitch.setValue(desiredAltitudeType != undefined? desiredAltitudeType == "ASL": undefined, false); this.#speedTypeSwitch.setValue(desiredSpeedType != undefined? desiredSpeedType == "CAS": undefined, false); @@ -328,7 +327,7 @@ export class UnitControlPanel extends Panel { } /* Send command and close */ - var units = getUnitsManager().getSelectedUnits(); + var units = getApp().getUnitsManager().getSelectedUnits(); if (units.length > 0) units[0].setAdvancedOptions(isTanker, isAWACS, TACAN, radio, generalSettings); diff --git a/client/src/panels/unitinfopanel.ts b/client/src/panels/unitinfopanel.ts index 99b8005b..206afe94 100644 --- a/client/src/panels/unitinfopanel.ts +++ b/client/src/panels/unitinfopanel.ts @@ -1,4 +1,3 @@ -import { Ammo } from "../@types/unit"; import { aircraftDatabase } from "../unit/databases/aircraftdatabase"; import { Unit } from "../unit/unit"; import { Panel } from "./panel"; @@ -13,12 +12,8 @@ export class UnitInfoPanel extends Panel { #unitLabel: HTMLElement; #unitName: HTMLElement; - /** - * - * @param ID - the ID of the HTML element which will contain the context menu - */ - constructor(ID: string){ - super(ID); + constructor(ID: string) { + super( ID ); this.#currentTask = (this.getElement().querySelector("#current-task")) as HTMLElement; this.#fuelBar = (this.getElement().querySelector("#fuel-bar")) as HTMLElement; diff --git a/client/src/plugin/pluginmanager.ts b/client/src/plugin/pluginmanager.ts new file mode 100644 index 00000000..38119b69 --- /dev/null +++ b/client/src/plugin/pluginmanager.ts @@ -0,0 +1,73 @@ +import path from "path"; +import { Manager } from "../other/manager"; +import { getApp } from ".."; + +/** The plugins manager is responsible for loading and initializing all the plugins. Plugins are located in the public/plugins folder. + * Each plugin must be comprised of a single folder containing a index.js file. Each plugin must set the globalThis.getOlympusPlugin variable to + * return a valid class implementing the OlympusPlugin interface. + */ + +export class PluginsManager extends Manager { + constructor() { + super(); + + var xhr = new XMLHttpRequest(); + xhr.open('GET', "/plugins/list", true); + xhr.responseType = 'json'; + xhr.onload = () => { + var status = xhr.status; + if (status === 200) { + this.#loadPlugins(xhr.response); + } else { + console.error(`Error retrieving plugins`) + } + }; + xhr.send(); + } + + #loadPlugins(pluginsFolders: string[]) { + pluginsFolders.forEach((pluginName: string) => { + var xhr = new XMLHttpRequest(); + xhr.open('GET', path.join("/plugins", pluginName, "index.js"), true); + xhr.responseType = 'text'; + xhr.onload = () => { + var status = xhr.status; + if (status === 200) { + /* Inject the plugin style */ + var link = document.createElement("link"); + link.href = path.join("/plugins", pluginName, "style.css"); + link.type = "text/css"; + link.rel = "stylesheet"; + document.getElementsByTagName("head")[0].appendChild(link); + + /* Evaluate the plugin javascript */ + var plugin: OlympusPlugin | null = null; + try { + eval(xhr.response); + plugin = globalThis.getOlympusPlugin() as OlympusPlugin; + console.log(plugin.getName() + " loaded correctly"); + } catch (error: any) { + console.log("An error occured while loading a plugin from " + pluginName); + console.log(error); + } + + /* If the plugin was loaded, try to initialize it */ + if (plugin != null) { + try { + if (plugin.initialize(getApp())) { + console.log(plugin.getName() + " initialized correctly"); + this.add(pluginName, plugin); + } + } catch (error: any) { + console.log("An error occured while initializing a plugin from " + pluginName); + console.log(error); + } + } + } else { + console.error(`Error retrieving plugin from ${pluginName}`) + } + }; + xhr.send(); + }) + } +} \ No newline at end of file diff --git a/client/src/popups/popup.ts b/client/src/popups/popup.ts index 55f828ac..37af5df8 100644 --- a/client/src/popups/popup.ts +++ b/client/src/popups/popup.ts @@ -1,6 +1,11 @@ import { Panel } from "../panels/panel"; export class Popup extends Panel { + + constructor( elementId:string ) { + super( elementId ); + } + #fadeTime: number = 2000; // Milliseconds #hideTimer: number | undefined = undefined; #visibilityTimer: number | undefined = undefined; diff --git a/client/src/server/dataextractor.ts b/client/src/server/dataextractor.ts index d22b6201..efd61d8b 100644 --- a/client/src/server/dataextractor.ts +++ b/client/src/server/dataextractor.ts @@ -1,5 +1,4 @@ import { LatLng } from "leaflet"; -import { Ammo, Contact, GeneralSettings, Offset, Radio, TACAN } from "../@types/unit"; export class DataExtractor { #seekPosition = 0; diff --git a/client/src/server/server.ts b/client/src/server/server.ts deleted file mode 100644 index 05695c86..00000000 --- a/client/src/server/server.ts +++ /dev/null @@ -1,489 +0,0 @@ -import { LatLng } from 'leaflet'; -import { getConnectionStatusPanel, getInfoPopup, getLogPanel, getMissionHandler, getServerStatusPanel, getUnitsManager, getWeaponsManager, setLoginStatus } from '..'; -import { GeneralSettings, Radio, TACAN } from '../@types/unit'; -import { AIRBASES_URI, BULLSEYE_URI, COMMANDS_URI, LOGS_URI, MISSION_URI, NONE, ROEs, UNITS_URI, WEAPONS_URI, emissionsCountermeasures, reactionsToThreat } from '../constants/constants'; - -var connected: boolean = false; -var paused: boolean = false; - -var REST_ADDRESS = "http://localhost:30000/olympus"; -var DEMO_ADDRESS = window.location.href + "demo"; - -var username = ""; -var password = ""; - -var sessionHash: string | null = null; -var lastUpdateTimes: {[key: string]: number} = {} -lastUpdateTimes[UNITS_URI] = Date.now(); -lastUpdateTimes[WEAPONS_URI] = Date.now(); -lastUpdateTimes[LOGS_URI] = Date.now(); -lastUpdateTimes[AIRBASES_URI] = Date.now(); -lastUpdateTimes[BULLSEYE_URI] = Date.now(); -lastUpdateTimes[MISSION_URI] = Date.now(); - -var demoEnabled = false; - -export function toggleDemoEnabled() { - demoEnabled = !demoEnabled; -} - -export function setCredentials(newUsername: string, newPassword: string) { - username = newUsername; - password = newPassword; -} - -export function GET(callback: CallableFunction, uri: string, options?: ServerRequestOptions, responseType?: string) { - var xmlHttp = new XMLHttpRequest(); - - /* Assemble the request options string */ - var optionsString = ''; - if (options?.time != undefined) - optionsString = `time=${options.time}`; - if (options?.commandHash != undefined) - optionsString = `commandHash=${options.commandHash}`; - - /* On the connection */ - xmlHttp.open("GET", `${demoEnabled ? DEMO_ADDRESS : REST_ADDRESS}/${uri}${optionsString ? `?${optionsString}` : ''}`, true); - - /* If provided, set the credentials */ - if (username && password) - xmlHttp.setRequestHeader("Authorization", "Basic " + btoa(`${username}:${password}`)); - - /* If specified, set the response type */ - if (responseType) - xmlHttp.responseType = responseType as XMLHttpRequestResponseType; - - xmlHttp.onload = function (e) { - if (xmlHttp.status == 200) { - /* Success */ - setConnected(true); - if (xmlHttp.responseType == 'arraybuffer') - lastUpdateTimes[uri] = callback(xmlHttp.response); - else { - const result = JSON.parse(xmlHttp.responseText); - lastUpdateTimes[uri] = callback(result); - - if (result.frameRate !== undefined && result.load !== undefined) - getServerStatusPanel().update(result.frameRate, result.load); - } - } else if (xmlHttp.status == 401) { - /* Bad credentials */ - console.error("Incorrect username/password"); - setLoginStatus("failed"); - } else { - /* Failure, probably disconnected */ - setConnected(false); - } - }; - xmlHttp.onerror = function (res) { - console.error("An error occurred during the XMLHttpRequest"); - setConnected(false); - }; - xmlHttp.send(null); -} - -export function POST(request: object, callback: CallableFunction) { - var xmlHttp = new XMLHttpRequest(); - xmlHttp.open("PUT", demoEnabled ? DEMO_ADDRESS : REST_ADDRESS); - xmlHttp.setRequestHeader("Content-Type", "application/json"); - if (username && password) - xmlHttp.setRequestHeader("Authorization", "Basic " + btoa(`${username}:${password}`)); - xmlHttp.onload = (res: any) => { - var res = JSON.parse(xmlHttp.responseText); - callback(res); - }; - xmlHttp.send(JSON.stringify(request)); -} - -export function getConfig(callback: CallableFunction) { - var xmlHttp = new XMLHttpRequest(); - xmlHttp.open("GET", window.location.href + "config", true); - xmlHttp.onload = function (e) { - var data = JSON.parse(xmlHttp.responseText); - callback(data); - }; - xmlHttp.onerror = function () { - console.error("An error occurred during the XMLHttpRequest, could not retrieve configuration file"); - }; - xmlHttp.send(null); -} - -export function setAddress(address: string, port: number) { - REST_ADDRESS = `http://${address}:${port}/olympus` - console.log(`Setting REST address to ${REST_ADDRESS}`) -} - -export function getAirbases(callback: CallableFunction) { - GET(callback, AIRBASES_URI); -} - -export function getBullseye(callback: CallableFunction) { - GET(callback, BULLSEYE_URI); -} - -export function getLogs(callback: CallableFunction, refresh: boolean = false) { - GET(callback, LOGS_URI, { time: refresh ? 0 : lastUpdateTimes[LOGS_URI]}); -} - -export function getMission(callback: CallableFunction) { - GET(callback, MISSION_URI); -} - -export function getUnits(callback: CallableFunction, refresh: boolean = false) { - GET(callback, UNITS_URI, { time: refresh ? 0 : lastUpdateTimes[UNITS_URI] }, 'arraybuffer'); -} - -export function getWeapons(callback: CallableFunction, refresh: boolean = false) { - GET(callback, WEAPONS_URI, { time: refresh ? 0 : lastUpdateTimes[WEAPONS_URI] }, 'arraybuffer'); -} - -export function isCommandExecuted(callback: CallableFunction, commandHash: string) { - GET(callback, COMMANDS_URI, { commandHash: commandHash}); -} - -export function addDestination(ID: number, path: any, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "path": path } - var data = { "setPath": command } - POST(data, callback); -} - -export function spawnSmoke(color: string, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "color": color, "location": latlng }; - var data = { "smoke": command } - POST(data, callback); -} - -export function spawnExplosion(intensity: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "intensity": intensity, "location": latlng }; - var data = { "explosion": command } - POST(data, callback); -} - -export function spawnAircrafts(units: any, coalition: string, airbaseName: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { - var command = { "units": units, "coalition": coalition, "airbaseName": airbaseName, "country": country, "immediate": immediate, "spawnPoints": spawnPoints }; - var data = { "spawnAircrafts": command } - POST(data, callback); -} - -export function spawnHelicopters(units: any, coalition: string, airbaseName: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { - var command = { "units": units, "coalition": coalition, "airbaseName": airbaseName, "country": country, "immediate": immediate, "spawnPoints": spawnPoints }; - var data = { "spawnHelicopters": command } - POST(data, callback); -} - -export function spawnGroundUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { - var command = { "units": units, "coalition": coalition, "country": country, "immediate": immediate, "spawnPoints": spawnPoints };; - var data = { "spawnGroundUnits": command } - POST(data, callback); -} - -export function spawnNavyUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { - var command = { "units": units, "coalition": coalition, "country": country, "immediate": immediate, "spawnPoints": spawnPoints }; - var data = { "spawnNavyUnits": command } - POST(data, callback); -} - -export function attackUnit(ID: number, targetID: number, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "targetID": targetID }; - var data = { "attackUnit": command } - POST(data, callback); -} - -export function followUnit(ID: number, targetID: number, offset: { "x": number, "y": number, "z": number }, callback: CallableFunction = () => {}) { - // X: front-rear, positive front - // Y: top-bottom, positive bottom - // Z: left-right, positive right - - var command = { "ID": ID, "targetID": targetID, "offsetX": offset["x"], "offsetY": offset["y"], "offsetZ": offset["z"] }; - var data = { "followUnit": command } - POST(data, callback); -} - -export function cloneUnits(units: {ID: number, location: LatLng}[], deleteOriginal: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { - var command = { "units": units, "deleteOriginal": deleteOriginal, "spawnPoints": spawnPoints }; - var data = { "cloneUnits": command } - POST(data, callback); -} - -export function deleteUnit(ID: number, explosion: boolean, immediate: boolean, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "explosion": explosion, "immediate": immediate }; - var data = { "deleteUnit": command } - POST(data, callback); -} - -export function landAt(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng }; - var data = { "landAt": command } - POST(data, callback); -} - -export function changeSpeed(ID: number, speedChange: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "change": speedChange } - var data = { "changeSpeed": command } - POST(data, callback); -} - -export function setSpeed(ID: number, speed: number, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "speed": speed } - var data = { "setSpeed": command } - POST(data, callback); -} - -export function setSpeedType(ID: number, speedType: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "speedType": speedType } - var data = { "setSpeedType": command } - POST(data, callback); -} - -export function changeAltitude(ID: number, altitudeChange: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "change": altitudeChange } - var data = { "changeAltitude": command } - POST(data, callback); -} - -export function setAltitudeType(ID: number, altitudeType: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "altitudeType": altitudeType } - var data = { "setAltitudeType": command } - POST(data, callback); -} - -export function setAltitude(ID: number, altitude: number, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "altitude": altitude } - var data = { "setAltitude": command } - POST(data, callback); -} - -export function createFormation(ID: number, isLeader: boolean, wingmenIDs: number[], callback: CallableFunction = () => {}) { - var command = { "ID": ID, "wingmenIDs": wingmenIDs, "isLeader": isLeader } - var data = { "setLeader": command } - POST(data, callback); -} - -export function setROE(ID: number, ROE: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "ROE": ROEs.indexOf(ROE) } - var data = { "setROE": command } - POST(data, callback); -} - -export function setReactionToThreat(ID: number, reactionToThreat: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "reactionToThreat": reactionsToThreat.indexOf(reactionToThreat) } - var data = { "setReactionToThreat": command } - POST(data, callback); -} - -export function setEmissionsCountermeasures(ID: number, emissionCountermeasure: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "emissionsCountermeasures": emissionsCountermeasures.indexOf(emissionCountermeasure) } - var data = { "setEmissionsCountermeasures": command } - POST(data, callback); -} - -export function setOnOff(ID: number, onOff: boolean, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "onOff": onOff } - var data = { "setOnOff": command } - POST(data, callback); -} - -export function setFollowRoads(ID: number, followRoads: boolean, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "followRoads": followRoads } - var data = { "setFollowRoads": command } - POST(data, callback); -} - -export function refuel(ID: number, callback: CallableFunction = () => {}) { - var command = { "ID": ID }; - var data = { "refuel": command } - POST(data, callback); -} - -export function bombPoint(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng } - var data = { "bombPoint": command } - POST(data, callback); -} - -export function carpetBomb(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng } - var data = { "carpetBomb": command } - POST(data, callback); -} - -export function bombBuilding(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng } - var data = { "bombBuilding": command } - POST(data, callback); -} - -export function fireAtArea(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng } - var data = { "fireAtArea": command } - POST(data, callback); -} - -export function setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => {}) { - var command = { - "ID": ID, - "isTanker": isTanker, - "isAWACS": isAWACS, - "TACAN": TACAN, - "radio": radio, - "generalSettings": generalSettings - }; - - var data = { "setAdvancedOptions": command }; - POST(data, callback); -} - -export function setCommandModeOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: {blue: number, red: number}, eras: string[], setupTime: number, callback: CallableFunction = () => {}) { - var command = { - "restrictSpawns": restrictSpawns, - "restrictToCoalition": restrictToCoalition, - "spawnPoints": spawnPoints, - "eras": eras, - "setupTime": setupTime - }; - - var data = { "setCommandModeOptions": command }; - POST(data, callback); -} - -export function startUpdate() { - window.setInterval(() => { - if (!getPaused()) { - getMission((data: MissionData) => { - checkSessionHash(data.sessionHash); - getMissionHandler()?.updateMission(data); - return data.time; - }); - } - }, 1000); - - window.setInterval(() => { - if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { - getAirbases((data: AirbasesData) => { - checkSessionHash(data.sessionHash); - getMissionHandler()?.updateAirbases(data); - return data.time; - }); - } - }, 10000); - - window.setInterval(() => { - if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE){ - getBullseye((data: BullseyesData) => { - checkSessionHash(data.sessionHash); - getMissionHandler()?.updateBullseyes(data); - return data.time; - }); - } - }, 10000); - - window.setInterval(() => { - if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { - getLogs((data: any) => { - checkSessionHash(data.sessionHash); - getLogPanel().appendLogs(data.logs) - return data.time; - }); - } - }, 1000); - - window.setInterval(() => { - if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { - getUnits((buffer: ArrayBuffer) => { - var time = getUnitsManager()?.update(buffer); - return time; - }, false); - } - }, 250); - - window.setInterval(() => { - if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { - getWeapons((buffer: ArrayBuffer) => { - var time = getWeaponsManager()?.update(buffer); - return time; - }, false); - } - }, 250); - - window.setInterval(() => { - if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { - getUnits((buffer: ArrayBuffer) => { - var time = getUnitsManager()?.update(buffer); - return time; - }, true); - getConnectionStatusPanel()?.update(getConnected()); - } - }, 5000); - - window.setInterval(() => { - if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { - getWeapons((buffer: ArrayBuffer) => { - var time = getWeaponsManager()?.update(buffer); - return time; - }, true); - } - }, 5000); -} - -export function refreshAll() { - getAirbases((data: AirbasesData) => { - checkSessionHash(data.sessionHash); - getMissionHandler()?.updateAirbases(data); - return data.time; - }); - - getBullseye((data: BullseyesData) => { - checkSessionHash(data.sessionHash); - getMissionHandler()?.updateBullseyes(data); - return data.time; - }); - - getLogs((data: any) => { - checkSessionHash(data.sessionHash); - getLogPanel().appendLogs(data.logs) - return data.time; - }); - - getWeapons((buffer: ArrayBuffer) => { - var time = getWeaponsManager()?.update(buffer); - return time; - }, true); - - getUnits((buffer: ArrayBuffer) => { - var time = getUnitsManager()?.update(buffer); - return time; - }, true); -} - -export function checkSessionHash(newSessionHash: string) { - if (sessionHash != null) { - if (newSessionHash !== sessionHash) - location.reload(); - } - else - sessionHash = newSessionHash; -} - -export function setConnected(newConnected: boolean) { - if (connected != newConnected) - newConnected ? getInfoPopup().setText("Connected to DCS Olympus server") : getInfoPopup().setText("Disconnected from DCS Olympus server"); - connected = newConnected; - - if (connected) { - document.querySelector("#splash-screen")?.classList.add("hide"); - document.querySelector("#gray-out")?.classList.add("hide"); - } -} - -export function getConnected() { - return connected; -} - -export function setPaused(newPaused: boolean) { - paused = newPaused; - paused ? getInfoPopup().setText("View paused") : getInfoPopup().setText("View unpaused"); -} - -export function getPaused() { - return paused; -} \ No newline at end of file diff --git a/client/src/server/servermanager.ts b/client/src/server/servermanager.ts new file mode 100644 index 00000000..d2747e69 --- /dev/null +++ b/client/src/server/servermanager.ts @@ -0,0 +1,493 @@ +import { LatLng } from 'leaflet'; +import { getApp } from '..'; +import { AIRBASES_URI, BULLSEYE_URI, COMMANDS_URI, LOGS_URI, MISSION_URI, NONE, ROEs, UNITS_URI, WEAPONS_URI, emissionsCountermeasures, reactionsToThreat } from '../constants/constants'; +import { ServerStatusPanel } from '../panels/serverstatuspanel'; +import { LogPanel } from '../panels/logpanel'; +import { Popup } from '../popups/popup'; +import { ConnectionStatusPanel } from '../panels/connectionstatuspanel'; + +export class ServerManager { + #connected: boolean = false; + #paused: boolean = false; + #REST_ADDRESS = "http://localhost:30000/olympus"; + #DEMO_ADDRESS = window.location.href + "demo"; + #username = ""; + #password = ""; + #sessionHash: string | null = null; + #lastUpdateTimes: {[key: string]: number} = {} + #demoEnabled = false; + + constructor() { + this.#lastUpdateTimes[UNITS_URI] = Date.now(); + this.#lastUpdateTimes[WEAPONS_URI] = Date.now(); + this.#lastUpdateTimes[LOGS_URI] = Date.now(); + this.#lastUpdateTimes[AIRBASES_URI] = Date.now(); + this.#lastUpdateTimes[BULLSEYE_URI] = Date.now(); + this.#lastUpdateTimes[MISSION_URI] = Date.now(); + } + + toggleDemoEnabled() { + this.#demoEnabled = !this.#demoEnabled; + } + + setCredentials(newUsername: string, newPassword: string) { + this.#username = newUsername; + this.#password = newPassword; + } + + GET(callback: CallableFunction, uri: string, options?: ServerRequestOptions, responseType?: string) { + var xmlHttp = new XMLHttpRequest(); + + /* Assemble the request options string */ + var optionsString = ''; + if (options?.time != undefined) + optionsString = `time=${options.time}`; + if (options?.commandHash != undefined) + optionsString = `commandHash=${options.commandHash}`; + + /* On the connection */ + xmlHttp.open("GET", `${this.#demoEnabled ? this.#DEMO_ADDRESS : this.#REST_ADDRESS}/${uri}${optionsString ? `?${optionsString}` : ''}`, true); + + /* If provided, set the credentials */ + if (this.#username && this.#password) + xmlHttp.setRequestHeader("Authorization", "Basic " + btoa(`${this.#username}:${this.#password}`)); + + /* If specified, set the response type */ + if (responseType) + xmlHttp.responseType = responseType as XMLHttpRequestResponseType; + + xmlHttp.onload = (e) => { + if (xmlHttp.status == 200) { + /* Success */ + this.setConnected(true); + if (xmlHttp.responseType == 'arraybuffer') + this.#lastUpdateTimes[uri] = callback(xmlHttp.response); + else { + const result = JSON.parse(xmlHttp.responseText); + this.#lastUpdateTimes[uri] = callback(result); + + if (result.frameRate !== undefined && result.load !== undefined) + (getApp().getPanelsManager().get("serverStatus") as ServerStatusPanel).update(result.frameRate, result.load); + } + } else if (xmlHttp.status == 401) { + /* Bad credentials */ + console.error("Incorrect username/password"); + getApp().setLoginStatus("failed"); + } else { + /* Failure, probably disconnected */ + this.setConnected(false); + } + }; + xmlHttp.onerror = (res) => { + console.error("An error occurred during the XMLHttpRequest"); + this.setConnected(false); + }; + xmlHttp.send(null); + } + + POST(request: object, callback: CallableFunction) { + var xmlHttp = new XMLHttpRequest(); + xmlHttp.open("PUT", this.#demoEnabled ? this.#DEMO_ADDRESS : this.#REST_ADDRESS); + xmlHttp.setRequestHeader("Content-Type", "application/json"); + if (this.#username && this.#password) + xmlHttp.setRequestHeader("Authorization", "Basic " + btoa(`${this.#username}:${this.#password}`)); + xmlHttp.onload = (res: any) => { + var res = JSON.parse(xmlHttp.responseText); + callback(res); + }; + xmlHttp.send(JSON.stringify(request)); + } + + getConfig(callback: CallableFunction) { + var xmlHttp = new XMLHttpRequest(); + xmlHttp.open("GET", window.location.href + "config", true); + xmlHttp.onload = function (e) { + var data = JSON.parse(xmlHttp.responseText); + callback(data); + }; + xmlHttp.onerror = function () { + console.error("An error occurred during the XMLHttpRequest, could not retrieve configuration file"); + }; + xmlHttp.send(null); + } + + setAddress(address: string, port: number) { + this.#REST_ADDRESS = `http://${address}:${port}/olympus` + console.log(`Setting REST address to ${this.#REST_ADDRESS}`) + } + + getAirbases(callback: CallableFunction) { + this.GET(callback, AIRBASES_URI); + } + + getBullseye(callback: CallableFunction) { + this.GET(callback, BULLSEYE_URI); + } + + getLogs(callback: CallableFunction, refresh: boolean = false) { + this.GET(callback, LOGS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[LOGS_URI]}); + } + + getMission(callback: CallableFunction) { + this.GET(callback, MISSION_URI); + } + + getUnits(callback: CallableFunction, refresh: boolean = false) { + this.GET(callback, UNITS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[UNITS_URI] }, 'arraybuffer'); + } + + getWeapons(callback: CallableFunction, refresh: boolean = false) { + this.GET(callback, WEAPONS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[WEAPONS_URI] }, 'arraybuffer'); + } + + isCommandExecuted(callback: CallableFunction, commandHash: string) { + this.GET(callback, COMMANDS_URI, { commandHash: commandHash}); + } + + addDestination(ID: number, path: any, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "path": path } + var data = { "setPath": command } + this.POST(data, callback); + } + + spawnSmoke(color: string, latlng: LatLng, callback: CallableFunction = () => {}) { + var command = { "color": color, "location": latlng }; + var data = { "smoke": command } + this.POST(data, callback); + } + + spawnExplosion(intensity: number, latlng: LatLng, callback: CallableFunction = () => {}) { + var command = { "intensity": intensity, "location": latlng }; + var data = { "explosion": command } + this.POST(data, callback); + } + + spawnAircrafts(units: any, coalition: string, airbaseName: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { + var command = { "units": units, "coalition": coalition, "airbaseName": airbaseName, "country": country, "immediate": immediate, "spawnPoints": spawnPoints }; + var data = { "spawnAircrafts": command } + this.POST(data, callback); + } + + spawnHelicopters(units: any, coalition: string, airbaseName: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { + var command = { "units": units, "coalition": coalition, "airbaseName": airbaseName, "country": country, "immediate": immediate, "spawnPoints": spawnPoints }; + var data = { "spawnHelicopters": command } + this.POST(data, callback); + } + + spawnGroundUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { + var command = { "units": units, "coalition": coalition, "country": country, "immediate": immediate, "spawnPoints": spawnPoints };; + var data = { "spawnGroundUnits": command } + this.POST(data, callback); + } + + spawnNavyUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { + var command = { "units": units, "coalition": coalition, "country": country, "immediate": immediate, "spawnPoints": spawnPoints }; + var data = { "spawnNavyUnits": command } + this.POST(data, callback); + } + + attackUnit(ID: number, targetID: number, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "targetID": targetID }; + var data = { "attackUnit": command } + this.POST(data, callback); + } + + followUnit(ID: number, targetID: number, offset: { "x": number, "y": number, "z": number }, callback: CallableFunction = () => {}) { + // X: front-rear, positive front + // Y: top-bottom, positive bottom + // Z: left-right, positive right + + var command = { "ID": ID, "targetID": targetID, "offsetX": offset["x"], "offsetY": offset["y"], "offsetZ": offset["z"] }; + var data = { "followUnit": command } + this.POST(data, callback); + } + + cloneUnits(units: {ID: number, location: LatLng}[], deleteOriginal: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { + var command = { "units": units, "deleteOriginal": deleteOriginal, "spawnPoints": spawnPoints }; + var data = { "cloneUnits": command } + this.POST(data, callback); + } + + deleteUnit(ID: number, explosion: boolean, immediate: boolean, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "explosion": explosion, "immediate": immediate }; + var data = { "deleteUnit": command } + this.POST(data, callback); + } + + landAt(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "location": latlng }; + var data = { "landAt": command } + this.POST(data, callback); + } + + changeSpeed(ID: number, speedChange: string, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "change": speedChange } + var data = { "changeSpeed": command } + this.POST(data, callback); + } + + setSpeed(ID: number, speed: number, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "speed": speed } + var data = { "setSpeed": command } + this.POST(data, callback); + } + + setSpeedType(ID: number, speedType: string, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "speedType": speedType } + var data = { "setSpeedType": command } + this.POST(data, callback); + } + + changeAltitude(ID: number, altitudeChange: string, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "change": altitudeChange } + var data = { "changeAltitude": command } + this.POST(data, callback); + } + + setAltitudeType(ID: number, altitudeType: string, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "altitudeType": altitudeType } + var data = { "setAltitudeType": command } + this.POST(data, callback); + } + + setAltitude(ID: number, altitude: number, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "altitude": altitude } + var data = { "setAltitude": command } + this.POST(data, callback); + } + + createFormation(ID: number, isLeader: boolean, wingmenIDs: number[], callback: CallableFunction = () => {}) { + var command = { "ID": ID, "wingmenIDs": wingmenIDs, "isLeader": isLeader } + var data = { "setLeader": command } + this.POST(data, callback); + } + + setROE(ID: number, ROE: string, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "ROE": ROEs.indexOf(ROE) } + var data = { "setROE": command } + this.POST(data, callback); + } + + setReactionToThreat(ID: number, reactionToThreat: string, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "reactionToThreat": reactionsToThreat.indexOf(reactionToThreat) } + var data = { "setReactionToThreat": command } + this.POST(data, callback); + } + + setEmissionsCountermeasures(ID: number, emissionCountermeasure: string, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "emissionsCountermeasures": emissionsCountermeasures.indexOf(emissionCountermeasure) } + var data = { "setEmissionsCountermeasures": command } + this.POST(data, callback); + } + + setOnOff(ID: number, onOff: boolean, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "onOff": onOff } + var data = { "setOnOff": command } + this.POST(data, callback); + } + + setFollowRoads(ID: number, followRoads: boolean, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "followRoads": followRoads } + var data = { "setFollowRoads": command } + this.POST(data, callback); + } + + refuel(ID: number, callback: CallableFunction = () => {}) { + var command = { "ID": ID }; + var data = { "refuel": command } + this.POST(data, callback); + } + + bombPoint(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "location": latlng } + var data = { "bombPoint": command } + this.POST(data, callback); + } + + carpetBomb(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "location": latlng } + var data = { "carpetBomb": command } + this.POST(data, callback); + } + + bombBuilding(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "location": latlng } + var data = { "bombBuilding": command } + this.POST(data, callback); + } + + fireAtArea(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "location": latlng } + var data = { "fireAtArea": command } + this.POST(data, callback); + } + + setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => {}) { + var command = { + "ID": ID, + "isTanker": isTanker, + "isAWACS": isAWACS, + "TACAN": TACAN, + "radio": radio, + "generalSettings": generalSettings + }; + + var data = { "setAdvancedOptions": command }; + this.POST(data, callback); + } + + setCommandModeOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: {blue: number, red: number}, eras: string[], setupTime: number, callback: CallableFunction = () => {}) { + var command = { + "restrictSpawns": restrictSpawns, + "restrictToCoalition": restrictToCoalition, + "spawnPoints": spawnPoints, + "eras": eras, + "setupTime": setupTime + }; + + var data = { "setCommandModeOptions": command }; + this.POST(data, callback); + } + + startUpdate() { + window.setInterval(() => { + if (!this.getPaused()) { + this.getMission((data: MissionData) => { + this.checkSessionHash(data.sessionHash); + getApp().getMissionManager()?.updateMission(data); + return data.time; + }); + } + }, 1000); + + window.setInterval(() => { + if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) { + this.getAirbases((data: AirbasesData) => { + this.checkSessionHash(data.sessionHash); + getApp().getMissionManager()?.updateAirbases(data); + return data.time; + }); + } + }, 10000); + + window.setInterval(() => { + if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE){ + this.getBullseye((data: BullseyesData) => { + this.checkSessionHash(data.sessionHash); + getApp().getMissionManager()?.updateBullseyes(data); + return data.time; + }); + } + }, 10000); + + window.setInterval(() => { + if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) { + this.getLogs((data: any) => { + this.checkSessionHash(data.sessionHash); + (getApp().getPanelsManager().get("log") as LogPanel).appendLogs(data.logs) + return data.time; + }); + } + }, 1000); + + window.setInterval(() => { + if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) { + this.getUnits((buffer: ArrayBuffer) => { + var time = getApp().getUnitsManager()?.update(buffer); + return time; + }, false); + } + }, 250); + + window.setInterval(() => { + if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) { + this.getWeapons((buffer: ArrayBuffer) => { + var time = getApp().getWeaponsManager()?.update(buffer); + return time; + }, false); + } + }, 250); + + window.setInterval(() => { + if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) { + this.getUnits((buffer: ArrayBuffer) => { + var time = getApp().getUnitsManager()?.update(buffer); + return time; + }, true); + (getApp().getPanelsManager().get("connectionStatus") as ConnectionStatusPanel).update(this.getConnected()); + } + }, 5000); + + window.setInterval(() => { + if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) { + this.getWeapons((buffer: ArrayBuffer) => { + var time = getApp().getWeaponsManager()?.update(buffer); + return time; + }, true); + } + }, 5000); + } + + refreshAll() { + this.getAirbases((data: AirbasesData) => { + this.checkSessionHash(data.sessionHash); + getApp().getMissionManager()?.updateAirbases(data); + return data.time; + }); + + this.getBullseye((data: BullseyesData) => { + this.checkSessionHash(data.sessionHash); + getApp().getMissionManager()?.updateBullseyes(data); + return data.time; + }); + + this.getLogs((data: any) => { + this.checkSessionHash(data.sessionHash); + (getApp().getPanelsManager().get("log") as LogPanel).appendLogs(data.logs) + return data.time; + }); + + this.getWeapons((buffer: ArrayBuffer) => { + var time = getApp().getWeaponsManager()?.update(buffer); + return time; + }, true); + + this.getUnits((buffer: ArrayBuffer) => { + var time = getApp().getUnitsManager()?.update(buffer); + return time; + }, true); + } + + checkSessionHash(newSessionHash: string) { + if (this.#sessionHash != null) { + if (newSessionHash !== this.#sessionHash) + location.reload(); + } + else + this.#sessionHash = newSessionHash; + } + + setConnected(newConnected: boolean) { + if (this.#connected != newConnected) + newConnected ? (getApp().getPopupsManager().get("infoPopup") as Popup).setText("Connected to DCS Olympus server") : (getApp().getPopupsManager().get("infoPopup") as Popup).setText("Disconnected from DCS Olympus server"); + this.#connected = newConnected; + + if (this.#connected) { + document.querySelector("#splash-screen")?.classList.add("hide"); + document.querySelector("#gray-out")?.classList.add("hide"); + } + } + + getConnected() { + return this.#connected; + } + + setPaused(newPaused: boolean) { + this.#paused = newPaused; + this.#paused ? (getApp().getPopupsManager().get("infoPopup") as Popup).setText("View paused") : (getApp().getPopupsManager().get("infoPopup") as Popup).setText("View unpaused"); + } + + getPaused() { + return this.#paused; + } +} diff --git a/client/src/shortcut/shortcut.ts b/client/src/shortcut/shortcut.ts new file mode 100644 index 00000000..095ba6cd --- /dev/null +++ b/client/src/shortcut/shortcut.ts @@ -0,0 +1,42 @@ +import { keyEventWasInInput } from "../other/utils"; + +export abstract class Shortcut { + #config: ShortcutOptions + + constructor(config: ShortcutOptions) { + this.#config = config; + } + + getConfig() { + return this.#config; + } +} + +export class ShortcutKeyboard extends Shortcut { + constructor(config: KeyboardShortcutOptions) { + config.event = config.event || "keyup"; + super(config); + + document.addEventListener(config.event, (ev: any) => { + if (ev instanceof KeyboardEvent === false || keyEventWasInInput(ev)) { + return; + } + + if (config.code !== ev.code) { + return; + } + + if (((typeof config.altKey !== "boolean") || (typeof config.altKey === "boolean" && ev.altKey === config.altKey)) + && ((typeof config.ctrlKey !== "boolean") || (typeof config.ctrlKey === "boolean" && ev.ctrlKey === config.ctrlKey)) + && ((typeof config.shiftKey !== "boolean") || (typeof config.shiftKey === "boolean" && ev.shiftKey === config.shiftKey))) { + config.callback(ev); + } + }); + } +} + +export class ShortcutMouse extends Shortcut { + constructor(config: MouseShortcutOptions) { + super(config); + } +} \ No newline at end of file diff --git a/client/src/shortcut/shortcutmanager.ts b/client/src/shortcut/shortcutmanager.ts new file mode 100644 index 00000000..6f1acd21 --- /dev/null +++ b/client/src/shortcut/shortcutmanager.ts @@ -0,0 +1,53 @@ +import { Manager } from "../other/manager"; +import { Shortcut } from "./shortcut"; + +export class ShortcutManager extends Manager { + + #keysBeingHeld: string[] = []; + #keyDownCallbacks: CallableFunction[] = []; + #keyUpCallbacks: CallableFunction[] = []; + + constructor() { + + super(); + + document.addEventListener("keydown", (ev: KeyboardEvent) => { + if (this.#keysBeingHeld.indexOf(ev.code) < 0) { + this.#keysBeingHeld.push(ev.code) + } + this.#keyDownCallbacks.forEach(callback => callback(ev)); + }); + + document.addEventListener("keyup", (ev: KeyboardEvent) => { + this.#keysBeingHeld = this.#keysBeingHeld.filter(held => held !== ev.code); + this.#keyUpCallbacks.forEach(callback => callback(ev)); + }); + + } + + add(name: string, shortcut: Shortcut) { + super.add(name, shortcut); + return this; + } + + getKeysBeingHeld() { + return this.#keysBeingHeld; + } + + keyComboMatches(combo: string[]) { + const heldKeys = this.getKeysBeingHeld(); + if (combo.length !== heldKeys.length) { + return false; + } + + return combo.every(key => heldKeys.indexOf(key) > -1); + } + + onKeyDown(callback: CallableFunction) { + this.#keyDownCallbacks.push(callback); + } + + onKeyUp(callback: CallableFunction) { + this.#keyUpCallbacks.push(callback); + } +} \ No newline at end of file diff --git a/client/src/unit/databases/aircraftdatabase.ts b/client/src/unit/databases/aircraftdatabase.ts index 31d072cb..74ecf23f 100644 --- a/client/src/unit/databases/aircraftdatabase.ts +++ b/client/src/unit/databases/aircraftdatabase.ts @@ -1,4 +1,4 @@ -import { getMissionHandler } from "../.."; +import { getApp } from "../.."; import { GAME_MASTER } from "../../constants/constants"; import { UnitDatabase } from "./unitdatabase" @@ -12,7 +12,7 @@ export class AircraftDatabase extends UnitDatabase { } getSpawnPointsByName(name: string) { - if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns) + if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns) return 0; const blueprint = this.getByName(name); diff --git a/client/src/unit/databases/groundunitdatabase.ts b/client/src/unit/databases/groundunitdatabase.ts index e34c6313..a4d8213a 100644 --- a/client/src/unit/databases/groundunitdatabase.ts +++ b/client/src/unit/databases/groundunitdatabase.ts @@ -1,4 +1,4 @@ -import { getMissionHandler } from "../.."; +import { getApp } from "../.."; import { GAME_MASTER } from "../../constants/constants"; import { UnitDatabase } from "./unitdatabase" @@ -8,7 +8,7 @@ export class GroundUnitDatabase extends UnitDatabase { } getSpawnPointsByName(name: string) { - if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns) + if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns) return 0; const blueprint = this.getByName(name); diff --git a/client/src/unit/databases/helicopterdatabase.ts b/client/src/unit/databases/helicopterdatabase.ts index a39de1c8..d105d282 100644 --- a/client/src/unit/databases/helicopterdatabase.ts +++ b/client/src/unit/databases/helicopterdatabase.ts @@ -1,4 +1,4 @@ -import { getMissionHandler } from "../.."; +import { getApp } from "../.."; import { GAME_MASTER } from "../../constants/constants"; import { UnitDatabase } from "./unitdatabase" @@ -8,7 +8,7 @@ export class HelicopterDatabase extends UnitDatabase { } getSpawnPointsByName(name: string) { - if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns) + if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns) return 0; const blueprint = this.getByName(name); diff --git a/client/src/unit/databases/navyunitdatabase.ts b/client/src/unit/databases/navyunitdatabase.ts index c45f07c2..6f5111eb 100644 --- a/client/src/unit/databases/navyunitdatabase.ts +++ b/client/src/unit/databases/navyunitdatabase.ts @@ -1,4 +1,4 @@ -import { getMissionHandler } from "../.."; +import { getApp } from "../.."; import { GAME_MASTER } from "../../constants/constants"; import { UnitDatabase } from "./unitdatabase" @@ -8,7 +8,7 @@ export class NavyUnitDatabase extends UnitDatabase { } getSpawnPointsByName(name: string) { - if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns) + if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns) return 0; const blueprint = this.getByName(name); diff --git a/client/src/unit/databases/unitdatabase.ts b/client/src/unit/databases/unitdatabase.ts index 92316d90..b64a6e01 100644 --- a/client/src/unit/databases/unitdatabase.ts +++ b/client/src/unit/databases/unitdatabase.ts @@ -1,7 +1,6 @@ import { LatLng } from "leaflet"; -import { getMissionHandler, getUnitsManager } from "../.."; +import { getApp } from "../.."; import { GAME_MASTER } from "../../constants/constants"; -import { UnitBlueprint } from "../../@types/unitdatabase"; export class UnitDatabase { blueprints: { [key: string]: UnitBlueprint } = {}; @@ -44,15 +43,15 @@ export class UnitDatabase { } getBlueprints() { - if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns) + if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns) return this.blueprints; else { var filteredBlueprints: { [key: string]: UnitBlueprint } = {}; for (let unit in this.blueprints) { const blueprint = this.blueprints[unit]; - if (this.getSpawnPointsByName(blueprint.name) <= getMissionHandler().getAvailableSpawnPoints() && - getMissionHandler().getCommandModeOptions().eras.includes(blueprint.era) && - (!getMissionHandler().getCommandModeOptions().restrictToCoalition || blueprint.coalition === getMissionHandler().getCommandedCoalition() || blueprint.coalition === undefined)) { + if (this.getSpawnPointsByName(blueprint.name) <= getApp().getMissionManager().getAvailableSpawnPoints() && + getApp().getMissionManager().getCommandModeOptions().eras.includes(blueprint.era) && + (!getApp().getMissionManager().getCommandModeOptions().restrictToCoalition || blueprint.coalition === getApp().getMissionManager().getCommandedCoalition() || blueprint.coalition === undefined)) { filteredBlueprints[unit] = blueprint; } } @@ -201,7 +200,7 @@ export class UnitDatabase { var row = Math.floor(idx / gridSize); var col = idx - row * gridSize; var location = new LatLng(initialPosition.lat + col * step, initialPosition.lng + row * step) - getUnitsManager().spawnUnits(this.getCategory(), [{unitType: unitBlueprint.name, location: location, altitude: 1000, loadout: "", liveryID: ""}]); + getApp().getUnitsManager().spawnUnits(this.getCategory(), [{unitType: unitBlueprint.name, location: location, altitude: 1000, loadout: "", liveryID: ""}]); }) } diff --git a/client/src/unit/unit.ts b/client/src/unit/unit.ts index 540ee7b7..60b801f8 100644 --- a/client/src/unit/unit.ts +++ b/client/src/unit/unit.ts @@ -1,18 +1,15 @@ import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker, Map, Point } from 'leaflet'; -import { getMap, getMissionHandler, getUnitsManager, getWeaponsManager } from '..'; +import { getApp } from '..'; import { enumToCoalition, enumToEmissioNCountermeasure, getMarkerCategoryByName, enumToROE, enumToReactionToThreat, enumToState, getUnitDatabaseByCategory, mToFt, msToKnots, rad2deg, bearing, deg2rad, ftToM } from '../other/utils'; -import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit, setEmissionsCountermeasures, setSpeedType, setAltitudeType, setOnOff, setFollowRoads, bombPoint, carpetBomb, bombBuilding, fireAtArea } from '../server/server'; import { CustomMarker } from '../map/markers/custommarker'; import { SVGInjector } from '@tanem/svg-injector'; import { UnitDatabase } from './databases/unitdatabase'; import { TargetMarker } from '../map/markers/targetmarker'; import { DLINK, DataIndexes, GAME_MASTER, HIDE_GROUP_MEMBERS, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, SHOW_CONTACT_LINES, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, VISUAL, emissionsCountermeasures, reactionsToThreat, states } from '../constants/constants'; -import { Ammo, Contact, GeneralSettings, Offset, Radio, TACAN, ObjectIconOptions, UnitData } from '../@types/unit'; import { DataExtractor } from '../server/dataextractor'; import { groundUnitDatabase } from './databases/groundunitdatabase'; import { navyUnitDatabase } from './databases/navyunitdatabase'; import { Weapon } from '../weapon/weapon'; -import { LoadoutBlueprint } from '../@types/unitdatabase'; var pathIcon = new Icon({ iconUrl: '/resources/theme/images/markers/marker-icon.png', @@ -147,7 +144,7 @@ export class Unit extends CustomMarker { this.#selectable = true; this.#pathPolyline = new Polyline([], { color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1 }); - this.#pathPolyline.addTo(getMap()); + this.#pathPolyline.addTo(getApp().getMap()); this.#contactsPolylines = []; this.#targetPositionMarker = new TargetMarker(new LatLng(0, 0)); this.#targetPositionPolyline = new Polyline([], { color: '#FF0000', weight: 3, opacity: 0.5, smoothFactor: 1 }); @@ -155,9 +152,17 @@ export class Unit extends CustomMarker { this.on('click', (e) => this.#onClick(e)); this.on('dblclick', (e) => this.#onDoubleClick(e)); this.on('contextmenu', (e) => this.#onContextMenu(e)); - this.on('mouseover', () => { if (this.belongsToCommandedCoalition()) this.setHighlighted(true); }) - this.on('mouseout', () => { this.setHighlighted(false); }) - getMap().on("zoomend", () => { this.#onZoom(); }) + this.on('mouseover', () => { + if (this.belongsToCommandedCoalition()) { + this.setHighlighted(true); + document.dispatchEvent(new CustomEvent("unitMouseover", { detail: this })); + } + }); + this.on('mouseout', () => { + this.setHighlighted(false); + document.dispatchEvent(new CustomEvent("unitMouseout", { detail: this })); + }); + getApp().getMap().on("zoomend", () => { this.#onZoom(); }) /* Deselect units if they are hidden */ document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => { @@ -182,7 +187,7 @@ export class Unit extends CustomMarker { /********************** Unit data *************************/ setData(dataExtractor: DataExtractor) { - var updateMarker = !getMap().hasLayer(this); + var updateMarker = !getApp().getMap().hasLayer(this); var datumIndex = 0; while (datumIndex != DataIndexes.endOfData) { @@ -235,7 +240,7 @@ export class Unit extends CustomMarker { if (updateMarker) this.#updateMarker(); - if (this.getSelected() || getMap().getCenterUnit() === this) + if (this.getSelected() || getApp().getMap().getCenterUnit() === this) document.dispatchEvent(new CustomEvent("unitUpdated", { detail: this })); } @@ -325,24 +330,29 @@ export class Unit extends CustomMarker { this.#selected = selected; if (selected) { - document.dispatchEvent(new CustomEvent("unitSelection", { detail: this })); this.#updateMarker(); } else { - document.dispatchEvent(new CustomEvent("unitDeselection", { detail: this })); this.#clearContacts(); this.#clearPath(); this.#clearTarget(); } this.getElement()?.querySelector(`.unit`)?.toggleAttribute("data-is-selected", selected); - if (this.getCategory() === "GroundUnit" && getMap().getZoom() < 13) { + if (this.getCategory() === "GroundUnit" && getApp().getMap().getZoom() < 13) { if (this.#isLeader) this.getGroupMembers().forEach((unit: Unit) => unit.setSelected(selected)); else this.#updateMarker(); } + // Trigger events after all (de-)selecting has been done + if (selected) { + document.dispatchEvent(new CustomEvent("unitSelection", { detail: this })); + } else { + document.dispatchEvent(new CustomEvent("unitDeselection", { detail: this })); + } + } } @@ -380,11 +390,11 @@ export class Unit extends CustomMarker { } getGroupMembers() { - return Object.values(getUnitsManager().getUnits()).filter((unit: Unit) => { return unit != this && unit.#groupName === this.#groupName; }); + return Object.values(getApp().getUnitsManager().getUnits()).filter((unit: Unit) => { return unit != this && unit.#groupName === this.#groupName; }); } belongsToCommandedCoalition() { - if (getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER && getMissionHandler().getCommandedCoalition() !== this.#coalition) + if (getApp().getMissionManager().getCommandModeOptions().commandMode !== GAME_MASTER && getApp().getMissionManager().getCommandedCoalition() !== this.#coalition) return false; return true; } @@ -510,13 +520,13 @@ export class Unit extends CustomMarker { /********************** Visibility *************************/ updateVisibility() { - const hiddenUnits = getMap().getHiddenTypes(); + const hiddenUnits = getApp().getMap().getHiddenTypes(); var hidden = ((this.#human && hiddenUnits.includes("human")) || (this.#controlled == false && hiddenUnits.includes("dcs")) || (hiddenUnits.includes(this.getMarkerCategory())) || (hiddenUnits.includes(this.#coalition)) || (!this.belongsToCommandedCoalition() && (this.#detectionMethods.length == 0 || (this.#detectionMethods.length == 1 && this.#detectionMethods[0] === RWR))) || - (getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getMap().getZoom() < 13 && (this.belongsToCommandedCoalition() || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0)))) && + (getApp().getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getApp().getMap().getZoom() < 13 && (this.belongsToCommandedCoalition() || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0)))) && !(this.getSelected()); this.setHidden(hidden || !this.#alive); @@ -526,16 +536,16 @@ export class Unit extends CustomMarker { this.#hidden = hidden; /* Add the marker if not present */ - if (!getMap().hasLayer(this) && !this.getHidden()) { - if (getMap().isZooming()) - this.once("zoomend", () => { this.addTo(getMap()) }) + if (!getApp().getMap().hasLayer(this) && !this.getHidden()) { + if (getApp().getMap().isZooming()) + this.once("zoomend", () => { this.addTo(getApp().getMap()) }) else - this.addTo(getMap()); + this.addTo(getApp().getMap()); } /* Hide the marker if necessary*/ - if (getMap().hasLayer(this) && this.getHidden()) { - getMap().removeLayer(this); + if (getApp().getMap().hasLayer(this) && this.getHidden()) { + getApp().getMap().removeLayer(this); } } @@ -560,7 +570,7 @@ export class Unit extends CustomMarker { } getLeader() { - return getUnitsManager().getUnitByID(this.#leaderID); + return getApp().getUnitsManager().getUnitByID(this.#leaderID); } canFulfillRole(roles: string | string[]) { @@ -578,7 +588,7 @@ export class Unit extends CustomMarker { isInViewport() { - const mapBounds = getMap().getBounds(); + const mapBounds = getApp().getMap().getBounds(); const unitPos = this.getPosition(); return (unitPos.lng > mapBounds.getWest() @@ -599,7 +609,7 @@ export class Unit extends CustomMarker { else { path = [latlng]; } - addDestination(this.ID, path); + getApp().getServerManager().addDestination(this.ID, path); } } @@ -612,109 +622,104 @@ export class Unit extends CustomMarker { /* Units can't attack themselves */ if (!this.#human) if (this.ID != targetID) - attackUnit(this.ID, targetID); + getApp().getServerManager().attackUnit(this.ID, targetID); } followUnit(targetID: number, offset: { "x": number, "y": number, "z": number }) { /* Units can't follow themselves */ if (!this.#human) if (this.ID != targetID) - followUnit(this.ID, targetID, offset); + getApp().getServerManager().followUnit(this.ID, targetID, offset); } landAt(latlng: LatLng) { if (!this.#human) - landAt(this.ID, latlng); + getApp().getServerManager().landAt(this.ID, latlng); } changeSpeed(speedChange: string) { if (!this.#human) - changeSpeed(this.ID, speedChange); + getApp().getServerManager().changeSpeed(this.ID, speedChange); } changeAltitude(altitudeChange: string) { if (!this.#human) - changeAltitude(this.ID, altitudeChange); + getApp().getServerManager().changeAltitude(this.ID, altitudeChange); } setSpeed(speed: number) { if (!this.#human) - setSpeed(this.ID, speed); + getApp().getServerManager().setSpeed(this.ID, speed); } setSpeedType(speedType: string) { if (!this.#human) - setSpeedType(this.ID, speedType); + getApp().getServerManager().setSpeedType(this.ID, speedType); } setAltitude(altitude: number) { if (!this.#human) - setAltitude(this.ID, altitude); + getApp().getServerManager().setAltitude(this.ID, altitude); } setAltitudeType(altitudeType: string) { if (!this.#human) - setAltitudeType(this.ID, altitudeType); + getApp().getServerManager().setAltitudeType(this.ID, altitudeType); } setROE(ROE: string) { if (!this.#human) - setROE(this.ID, ROE); + getApp().getServerManager().setROE(this.ID, ROE); } setReactionToThreat(reactionToThreat: string) { if (!this.#human) - setReactionToThreat(this.ID, reactionToThreat); + getApp().getServerManager().setReactionToThreat(this.ID, reactionToThreat); } setEmissionsCountermeasures(emissionCountermeasure: string) { if (!this.#human) - setEmissionsCountermeasures(this.ID, emissionCountermeasure); - } - - setLeader(isLeader: boolean, wingmenIDs: number[] = []) { - if (!this.#human) - setLeader(this.ID, isLeader, wingmenIDs); + getApp().getServerManager().setEmissionsCountermeasures(this.ID, emissionCountermeasure); } setOnOff(onOff: boolean) { if (!this.#human) - setOnOff(this.ID, onOff); + getApp().getServerManager().setOnOff(this.ID, onOff); } setFollowRoads(followRoads: boolean) { if (!this.#human) - setFollowRoads(this.ID, followRoads); + getApp().getServerManager().setFollowRoads(this.ID, followRoads); } delete(explosion: boolean, immediate: boolean) { - deleteUnit(this.ID, explosion, immediate); + getApp().getServerManager().deleteUnit(this.ID, explosion, immediate); } refuel() { if (!this.#human) - refuel(this.ID); + getApp().getServerManager().refuel(this.ID); } setAdvancedOptions(isTanker: boolean, isAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings) { if (!this.#human) - setAdvacedOptions(this.ID, isTanker, isAWACS, TACAN, radio, generalSettings); + getApp().getServerManager().setAdvacedOptions(this.ID, isTanker, isAWACS, TACAN, radio, generalSettings); } bombPoint(latlng: LatLng) { - bombPoint(this.ID, latlng); + getApp().getServerManager().bombPoint(this.ID, latlng); } carpetBomb(latlng: LatLng) { - carpetBomb(this.ID, latlng); + getApp().getServerManager().carpetBomb(this.ID, latlng); } bombBuilding(latlng: LatLng) { - bombBuilding(this.ID, latlng); + getApp().getServerManager().bombBuilding(this.ID, latlng); } fireAtArea(latlng: LatLng) { - fireAtArea(this.ID, latlng); + getApp().getServerManager().fireAtArea(this.ID, latlng); } /***********************************************/ @@ -726,9 +731,9 @@ export class Unit extends CustomMarker { /***********************************************/ #onClick(e: any) { if (!this.#preventClick) { - if (getMap().getState() === IDLE || getMap().getState() === MOVE_UNIT || e.originalEvent.ctrlKey) { + if (getApp().getMap().getState() === IDLE || getApp().getMap().getState() === MOVE_UNIT || e.originalEvent.ctrlKey) { if (!e.originalEvent.ctrlKey) - getUnitsManager().deselectAllUnits(); + getApp().getUnitsManager().deselectAllUnits(); this.setSelected(!this.getSelected()); const detail = { "detail": { "unit": this } }; @@ -743,7 +748,7 @@ export class Unit extends CustomMarker { } #onDoubleClick(e: any) { - const unitsManager = getUnitsManager(); + const unitsManager = getApp().getUnitsManager(); Object.values(unitsManager.getUnits()).forEach((unit: Unit) => { if (unit.getAlive() === true && unit.getName() === this.getName() && unit.isInViewport()) unitsManager.selectUnit(unit.ID, false); @@ -755,14 +760,14 @@ export class Unit extends CustomMarker { #onContextMenu(e: any) { var options: { [key: string]: { text: string, tooltip: string } } = {}; - const selectedUnits = getUnitsManager().getSelectedUnits(); - const selectedUnitTypes = getUnitsManager().getSelectedUnitsCategories(); + const selectedUnits = getApp().getUnitsManager().getSelectedUnits(); + const selectedUnitTypes = getApp().getUnitsManager().getSelectedUnitsCategories(); options["center-map"] = { text: "Center map", tooltip: "Center the map on the unit and follow it" }; if (selectedUnits.length > 0 && !(selectedUnits.length == 1 && (selectedUnits.includes(this)))) { options["attack"] = { text: "Attack", tooltip: "Attack the unit using A/A or A/G weapons" }; - if (getUnitsManager().getSelectedUnitsCategories().length == 1 && getUnitsManager().getSelectedUnitsCategories()[0] === "Aircraft") + if (getApp().getUnitsManager().getSelectedUnitsCategories().length == 1 && getApp().getUnitsManager().getSelectedUnitsCategories()[0] === "Aircraft") options["follow"] = { text: "Follow", tooltip: "Follow the unit at a user defined distance and position" };; } else if ((selectedUnits.length > 0 && (selectedUnits.includes(this))) || selectedUnits.length == 0) { @@ -771,13 +776,13 @@ export class Unit extends CustomMarker { } } - if (selectedUnitTypes.length === 1 && ["NavyUnit", "GroundUnit"].includes(selectedUnitTypes[0]) && getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getCoalition()}) !== undefined) + if (selectedUnitTypes.length === 1 && ["NavyUnit", "GroundUnit"].includes(selectedUnitTypes[0]) && getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getCoalition()}) !== undefined) options["group"] = { text: "Create group", tooltip: "Create a group from the selected units." }; if (Object.keys(options).length > 0) { - getMap().showUnitContextMenu(e.originalEvent.x, e.originalEvent.y, e.latlng); - getMap().getUnitContextMenu().setOptions(options, (option: string) => { - getMap().hideUnitContextMenu(); + getApp().getMap().showUnitContextMenu(e.originalEvent.x, e.originalEvent.y, e.latlng); + getApp().getMap().getUnitContextMenu().setOptions(options, (option: string) => { + getApp().getMap().hideUnitContextMenu(); this.#executeAction(e, option); }); } @@ -785,13 +790,13 @@ export class Unit extends CustomMarker { #executeAction(e: any, action: string) { if (action === "center-map") - getMap().centerOnUnit(this.ID); + getApp().getMap().centerOnUnit(this.ID); if (action === "attack") - getUnitsManager().selectedUnitsAttackUnit(this.ID); + getApp().getUnitsManager().selectedUnitsAttackUnit(this.ID); else if (action === "refuel") - getUnitsManager().selectedUnitsRefuel(); + getApp().getUnitsManager().selectedUnitsRefuel(); else if (action === "group") - getUnitsManager().selectedUnitsCreateGroup(); + getApp().getUnitsManager().selectedUnitsCreateGroup(); else if (action === "follow") this.#showFollowOptions(e); } @@ -810,12 +815,12 @@ export class Unit extends CustomMarker { 'custom': { text: "Custom", tooltip: "Set a custom formation position" }, } - getMap().getUnitContextMenu().setOptions(options, (option: string) => { - getMap().hideUnitContextMenu(); + getApp().getMap().getUnitContextMenu().setOptions(options, (option: string) => { + getApp().getMap().hideUnitContextMenu(); this.#applyFollowOptions(option); }); - getMap().showUnitContextMenu(e.originalEvent.x, e.originalEvent.y, e.latlng); + getApp().getMap().showUnitContextMenu(e.originalEvent.x, e.originalEvent.y, e.latlng); } #applyFollowOptions(action: string) { @@ -843,12 +848,12 @@ export class Unit extends CustomMarker { var y = upDown; var z = distance * Math.sin(angleRad); - getUnitsManager().selectedUnitsFollowUnit(this.ID, { "x": x, "y": y, "z": z }); + getApp().getUnitsManager().selectedUnitsFollowUnit(this.ID, { "x": x, "y": y, "z": z }); } }); } else { - getUnitsManager().selectedUnitsFollowUnit(this.ID, undefined, action); + getApp().getUnitsManager().selectedUnitsFollowUnit(this.ID, undefined, action); } } @@ -866,7 +871,7 @@ export class Unit extends CustomMarker { this.#miniMapMarker.setStyle({ color: "#ff5858" }); else this.#miniMapMarker.setStyle({ color: "#247be2" }); - this.#miniMapMarker.addTo(getMap().getMiniMapLayerGroup()); + this.#miniMapMarker.addTo(getApp().getMap().getMiniMapLayerGroup()); this.#miniMapMarker.bringToBack(); } else { @@ -877,8 +882,8 @@ export class Unit extends CustomMarker { } } else { - if (this.#miniMapMarker != null && getMap().getMiniMapLayerGroup().hasLayer(this.#miniMapMarker)) { - getMap().getMiniMapLayerGroup().removeLayer(this.#miniMapMarker); + if (this.#miniMapMarker != null && getApp().getMap().getMiniMapLayerGroup().hasLayer(this.#miniMapMarker)) { + getApp().getMap().getMiniMapLayerGroup().removeLayer(this.#miniMapMarker); this.#miniMapMarker = null; } } @@ -963,25 +968,25 @@ export class Unit extends CustomMarker { } /* Set vertical offset for altitude stacking */ - var pos = getMap().latLngToLayerPoint(this.getLatLng()).round(); + var pos = getApp().getMap().latLngToLayerPoint(this.getLatLng()).round(); this.setZIndexOffset(1000 + Math.floor(this.#position.alt as number) - pos.y + (this.#highlighted || this.#selected ? 5000 : 0)); } } #drawPath() { - if (this.#activePath != undefined && getMap().getVisibilityOptions()[SHOW_UNIT_PATHS]) { + if (this.#activePath != undefined && getApp().getMap().getVisibilityOptions()[SHOW_UNIT_PATHS]) { var points = []; points.push(new LatLng(this.#position.lat, this.#position.lng)); /* Add markers if missing */ while (this.#pathMarkers.length < Object.keys(this.#activePath).length) { - var marker = new Marker([0, 0], { icon: pathIcon }).addTo(getMap()); + var marker = new Marker([0, 0], { icon: pathIcon }).addTo(getApp().getMap()); this.#pathMarkers.push(marker); } /* Remove markers if too many */ while (this.#pathMarkers.length > Object.keys(this.#activePath).length) { - getMap().removeLayer(this.#pathMarkers[this.#pathMarkers.length - 1]); + getApp().getMap().removeLayer(this.#pathMarkers[this.#pathMarkers.length - 1]); this.#pathMarkers.splice(this.#pathMarkers.length - 1, 1) } @@ -1003,7 +1008,7 @@ export class Unit extends CustomMarker { #clearPath() { for (let WP in this.#pathMarkers) { - getMap().removeLayer(this.#pathMarkers[WP]); + getApp().getMap().removeLayer(this.#pathMarkers[WP]); } this.#pathMarkers = []; this.#pathPolyline.setLatLngs([]); @@ -1011,25 +1016,25 @@ export class Unit extends CustomMarker { #drawContacts() { this.#clearContacts(); - if (getMap().getVisibilityOptions()[SHOW_CONTACT_LINES]) { + if (getApp().getMap().getVisibilityOptions()[SHOW_CONTACT_LINES]) { for (let index in this.#contacts) { var contactData = this.#contacts[index]; var contact: Unit | Weapon | null; - if (contactData.ID in getUnitsManager().getUnits()) - contact = getUnitsManager().getUnitByID(contactData.ID); + if (contactData.ID in getApp().getUnitsManager().getUnits()) + contact = getApp().getUnitsManager().getUnitByID(contactData.ID); else - contact = getWeaponsManager().getWeaponByID(contactData.ID); + contact = getApp().getWeaponsManager().getWeaponByID(contactData.ID); if (contact != null && contact.getAlive()) { var startLatLng = new LatLng(this.#position.lat, this.#position.lng); var endLatLng: LatLng; if (contactData.detectionMethod === RWR) { var bearingToContact = bearing(this.#position.lat, this.#position.lng, contact.getPosition().lat, contact.getPosition().lng); - var startXY = getMap().latLngToContainerPoint(startLatLng); + var startXY = getApp().getMap().latLngToContainerPoint(startLatLng); var endX = startXY.x + 80 * Math.sin(deg2rad(bearingToContact)); var endY = startXY.y - 80 * Math.cos(deg2rad(bearingToContact)); - endLatLng = getMap().containerPointToLatLng(new Point(endX, endY)); + endLatLng = getApp().getMap().containerPointToLatLng(new Point(endX, endY)); } else endLatLng = new LatLng(contact.getPosition().lat, contact.getPosition().lng); @@ -1044,7 +1049,7 @@ export class Unit extends CustomMarker { else color = "#FFFFFF"; var contactPolyline = new Polyline([startLatLng, endLatLng], { color: color, weight: 3, opacity: 1, smoothFactor: 1, dashArray: "4, 8" }); - contactPolyline.addTo(getMap()); + contactPolyline.addTo(getApp().getMap()); this.#contactsPolylines.push(contactPolyline) } } @@ -1053,17 +1058,17 @@ export class Unit extends CustomMarker { #clearContacts() { for (let index in this.#contactsPolylines) { - getMap().removeLayer(this.#contactsPolylines[index]) + getApp().getMap().removeLayer(this.#contactsPolylines[index]) } } #drawTarget() { - if (this.#targetPosition.lat != 0 && this.#targetPosition.lng != 0 && getMap().getVisibilityOptions()[SHOW_UNIT_PATHS]) { + if (this.#targetPosition.lat != 0 && this.#targetPosition.lng != 0 && getApp().getMap().getVisibilityOptions()[SHOW_UNIT_PATHS]) { this.#drawTargetPosition(this.#targetPosition); } - else if (this.#targetID != 0 && getMap().getVisibilityOptions()[SHOW_UNIT_TARGETS]) { - const target = getUnitsManager().getUnitByID(this.#targetID); - if (target && (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || (this.belongsToCommandedCoalition() && getUnitsManager().getUnitDetectedMethods(target).some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))))) { + else if (this.#targetID != 0 && getApp().getMap().getVisibilityOptions()[SHOW_UNIT_TARGETS]) { + const target = getApp().getUnitsManager().getUnitByID(this.#targetID); + if (target && (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || (this.belongsToCommandedCoalition() && getApp().getUnitsManager().getUnitDetectedMethods(target).some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))))) { this.#drawTargetPosition(target.getPosition()); } } @@ -1072,20 +1077,20 @@ export class Unit extends CustomMarker { } #drawTargetPosition(targetPosition: LatLng) { - if (!getMap().hasLayer(this.#targetPositionMarker)) - this.#targetPositionMarker.addTo(getMap()); - if (!getMap().hasLayer(this.#targetPositionPolyline)) - this.#targetPositionPolyline.addTo(getMap()); + if (!getApp().getMap().hasLayer(this.#targetPositionMarker)) + this.#targetPositionMarker.addTo(getApp().getMap()); + if (!getApp().getMap().hasLayer(this.#targetPositionPolyline)) + this.#targetPositionPolyline.addTo(getApp().getMap()); this.#targetPositionMarker.setLatLng(new LatLng(targetPosition.lat, targetPosition.lng)); this.#targetPositionPolyline.setLatLngs([new LatLng(this.#position.lat, this.#position.lng), new LatLng(targetPosition.lat, targetPosition.lng)]) } #clearTarget() { - if (getMap().hasLayer(this.#targetPositionMarker)) - this.#targetPositionMarker.removeFrom(getMap()); + if (getApp().getMap().hasLayer(this.#targetPositionMarker)) + this.#targetPositionMarker.removeFrom(getApp().getMap()); - if (getMap().hasLayer(this.#targetPositionPolyline)) - this.#targetPositionPolyline.removeFrom(getMap()); + if (getApp().getMap().hasLayer(this.#targetPositionPolyline)) + this.#targetPositionPolyline.removeFrom(getApp().getMap()); } #onZoom() { diff --git a/client/src/unit/unitsmanager.ts b/client/src/unit/unitsmanager.ts index cf1808a3..4feda9e4 100644 --- a/client/src/unit/unitsmanager.ts +++ b/client/src/unit/unitsmanager.ts @@ -1,18 +1,18 @@ import { LatLng, LatLngBounds } from "leaflet"; -import { getHotgroupPanel, getInfoPopup, getMap, getMissionHandler, getUnitsManager, getWeaponsManager } from ".."; +import { getApp } from ".."; import { Unit } from "./unit"; -import { cloneUnits, deleteUnit, spawnAircrafts, spawnGroundUnits, spawnHelicopters, spawnNavyUnits } from "../server/server"; import { bearingAndDistanceToLatLng, deg2rad, getUnitDatabaseByCategory, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polyContains, polygonArea, randomPointInPoly, randomUnitBlueprint } from "../other/utils"; import { CoalitionArea } from "../map/coalitionarea/coalitionarea"; import { groundUnitDatabase } from "./databases/groundunitdatabase"; import { DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT } from "../constants/constants"; import { DataExtractor } from "../server/dataextractor"; -import { Contact, UnitData, UnitSpawnTable } from "../@types/unit"; import { citiesDatabase } from "./citiesDatabase"; import { aircraftDatabase } from "./databases/aircraftdatabase"; import { helicopterDatabase } from "./databases/helicopterdatabase"; import { navyUnitDatabase } from "./databases/navyunitdatabase"; import { TemporaryUnitMarker } from "../map/markers/temporaryunitmarker"; +import { Popup } from "../popups/popup"; +import { HotgroupPanel } from "../panels/hotgrouppanel"; /** The UnitsManager handles the creation, update, and control of units. Data is strictly updated by the server ONLY. This means that any interaction from the user will always and only * result in a command to the server, executed by means of a REST PUT request. Any subsequent change in data will be reflected only when the new data is sent back by the server. This strategy allows @@ -124,12 +124,12 @@ export class UnitsManager { /* If we are not in Game Master mode, visibility of units by the user is determined by the detections of the units themselves. This is performed here. This operation is computationally expensive, therefore it is only performed when #requestDetectionUpdate is true. This happens whenever a change in the detectionUpdates is detected */ - if (this.#requestDetectionUpdate && getMissionHandler().getCommandModeOptions().commandMode != GAME_MASTER) { + if (this.#requestDetectionUpdate && getApp().getMissionManager().getCommandModeOptions().commandMode != GAME_MASTER) { /* Create a dictionary of empty detection methods arrays */ var detectionMethods: { [key: string]: number[] } = {}; for (let ID in this.#units) detectionMethods[ID] = []; - for (let ID in getWeaponsManager().getWeapons()) + for (let ID in getApp().getWeaponsManager().getWeapons()) detectionMethods[ID] = []; /* Fill the array with the detection methods */ @@ -152,8 +152,8 @@ export class UnitsManager { } /* Set the detection methods for every weapon (weapons must be detected too) */ - for (let ID in getWeaponsManager().getWeapons()) { - const weapon = getWeaponsManager().getWeaponByID(parseInt(ID)); + for (let ID in getApp().getWeaponsManager().getWeapons()) { + const weapon = getApp().getWeaponsManager().getWeaponByID(parseInt(ID)); weapon?.setDetectionMethods(detectionMethods[ID]); } @@ -634,9 +634,9 @@ export class UnitsManager { var unit = selectedUnits[idx]; units.push({ ID: unit.ID, location: unit.getPosition() }); } - cloneUnits(units, true, 0 /* No spawn points, we delete the original units */); + getApp().getServerManager().cloneUnits(units, true, 0 /* No spawn points, we delete the original units */); } else { - getInfoPopup().setText(`Groups can only be created from units of the same category`); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText(`Groups can only be created from units of the same category`); } } @@ -659,7 +659,7 @@ export class UnitsManager { selectedUnits[idx].setHotgroup(hotgroup); } this.#showActionMessage(selectedUnits, `added to hotgroup ${hotgroup}`); - getHotgroupPanel().refreshHotgroups(); + (getApp().getPanelsManager().get("hotgroup") as HotgroupPanel).refreshHotgroups(); } /** Delete the selected units @@ -730,7 +730,7 @@ export class UnitsManager { selectedUnitsCopy() { /* A JSON is used to deepcopy the units, creating a "snapshot" of their properties at the time of the copy */ this.#copiedUnits = JSON.parse(JSON.stringify(this.getSelectedUnits().map((unit: Unit) => { return unit.getData() }))); /* Can be applied to humans too */ - getInfoPopup().setText(`${this.#copiedUnits.length} units copied`); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText(`${this.#copiedUnits.length} units copied`); } /*********************** Unit manipulation functions ************************/ @@ -742,9 +742,9 @@ export class UnitsManager { let spawnPoints = 0; /* If spawns are restricted, check that the user has the necessary spawn points */ - if (getMissionHandler().getCommandModeOptions().commandMode != GAME_MASTER) { - if (getMissionHandler().getCommandModeOptions().restrictSpawns && getMissionHandler().getRemainingSetupTime() < 0) { - getInfoPopup().setText(`Units can be pasted only during SETUP phase`); + if (getApp().getMissionManager().getCommandModeOptions().commandMode != GAME_MASTER) { + if (getApp().getMissionManager().getCommandModeOptions().restrictSpawns && getApp().getMissionManager().getRemainingSetupTime() < 0) { + (getApp().getPopupsManager().get("infoPopup") as Popup).setText(`Units can be pasted only during SETUP phase`); return false; } @@ -754,8 +754,8 @@ export class UnitsManager { spawnPoints += unitSpawnPoints; }) - if (spawnPoints > getMissionHandler().getAvailableSpawnPoints()) { - getInfoPopup().setText("Not enough spawn points available!"); + if (spawnPoints > getApp().getMissionManager().getAvailableSpawnPoints()) { + (getApp().getPopupsManager().get("infoPopup") as Popup).setText("Not enough spawn points available!"); return false; } } @@ -784,12 +784,12 @@ export class UnitsManager { var units: { ID: number, location: LatLng }[] = []; let markers: TemporaryUnitMarker[] = []; groups[groupName].forEach((unit: UnitData) => { - var position = new LatLng(getMap().getMouseCoordinates().lat + unit.position.lat - avgLat, getMap().getMouseCoordinates().lng + unit.position.lng - avgLng); - markers.push(getMap().addTemporaryMarker(position, unit.name, unit.coalition)); + var position = new LatLng(getApp().getMap().getMouseCoordinates().lat + unit.position.lat - avgLat, getApp().getMap().getMouseCoordinates().lng + unit.position.lng - avgLng); + markers.push(getApp().getMap().addTemporaryMarker(position, unit.name, unit.coalition)); units.push({ ID: unit.ID, location: position }); }); - cloneUnits(units, false, spawnPoints, (res: any) => { + getApp().getServerManager().cloneUnits(units, false, spawnPoints, (res: any) => { if (res.commandHash !== undefined) { markers.forEach((marker: TemporaryUnitMarker) => { marker.setCommandHash(res.commandHash); @@ -797,10 +797,10 @@ export class UnitsManager { } }); } - getInfoPopup().setText(`${this.#copiedUnits.length} units pasted`); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText(`${this.#copiedUnits.length} units pasted`); } else { - getInfoPopup().setText("No units copied!"); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText("No units copied!"); } } @@ -888,7 +888,7 @@ export class UnitsManager { var units = aliveUnits.map((unit: UnitData) => { return { unitType: unit.name, location: unit.position, liveryID: "" } }); - getUnitsManager().spawnUnits(groups[groupName][0].category, units, groups[groupName][0].coalition, true); + getApp().getUnitsManager().spawnUnits(groups[groupName][0].category, units, groups[groupName][0].coalition, true); } } }; @@ -911,46 +911,46 @@ export class UnitsManager { spawnUnits(category: string, units: UnitSpawnTable[], coalition: string = "blue", immediate: boolean = true, airbase: string = "", country: string = "", callback: CallableFunction = () => {}) { var spawnPoints = 0; var spawnFunction = () => {}; - var spawnsRestricted = getMissionHandler().getCommandModeOptions().restrictSpawns && getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER; + var spawnsRestricted = getApp().getMissionManager().getCommandModeOptions().restrictSpawns && getApp().getMissionManager().getRemainingSetupTime() < 0 && getApp().getMissionManager().getCommandModeOptions().commandMode !== GAME_MASTER; if (category === "Aircraft") { if (airbase == "" && spawnsRestricted) { - getInfoPopup().setText("Aircrafts can be air spawned during the SETUP phase only"); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText("Aircrafts can be air spawned during the SETUP phase only"); return false; } spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {return points + aircraftDatabase.getSpawnPointsByName(unit.unitType)}, 0); - spawnFunction = () => spawnAircrafts(units, coalition, airbase, country, immediate, spawnPoints, callback); + spawnFunction = () => getApp().getServerManager().spawnAircrafts(units, coalition, airbase, country, immediate, spawnPoints, callback); } else if (category === "Helicopter") { if (airbase == "" && spawnsRestricted) { - getInfoPopup().setText("Helicopters can be air spawned during the SETUP phase only"); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText("Helicopters can be air spawned during the SETUP phase only"); return false; } spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {return points + helicopterDatabase.getSpawnPointsByName(unit.unitType)}, 0); - spawnFunction = () => spawnHelicopters(units, coalition, airbase, country, immediate, spawnPoints, callback); + spawnFunction = () => getApp().getServerManager().spawnHelicopters(units, coalition, airbase, country, immediate, spawnPoints, callback); } else if (category === "GroundUnit") { if (spawnsRestricted) { - getInfoPopup().setText("Ground units can be spawned during the SETUP phase only"); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText("Ground units can be spawned during the SETUP phase only"); return false; } spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {return points + groundUnitDatabase.getSpawnPointsByName(unit.unitType)}, 0); - spawnFunction = () => spawnGroundUnits(units, coalition, country, immediate, spawnPoints, callback); + spawnFunction = () => getApp().getServerManager().spawnGroundUnits(units, coalition, country, immediate, spawnPoints, callback); } else if (category === "NavyUnit") { if (spawnsRestricted) { - getInfoPopup().setText("Navy units can be spawned during the SETUP phase only"); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText("Navy units can be spawned during the SETUP phase only"); return false; } spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {return points + navyUnitDatabase.getSpawnPointsByName(unit.unitType)}, 0); - spawnFunction = () => spawnNavyUnits(units, coalition, country, immediate, spawnPoints, callback); + spawnFunction = () => getApp().getServerManager().spawnNavyUnits(units, coalition, country, immediate, spawnPoints, callback); } - if (spawnPoints <= getMissionHandler().getAvailableSpawnPoints()) { - getMissionHandler().setSpentSpawnPoints(spawnPoints); + if (spawnPoints <= getApp().getMissionManager().getAvailableSpawnPoints()) { + getApp().getMissionManager().setSpentSpawnPoints(spawnPoints); spawnFunction(); return true; } else { - getInfoPopup().setText("Not enough spawn points available!"); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText("Not enough spawn points available!"); return false; } } @@ -969,7 +969,7 @@ export class UnitsManager { if (this.getSelectedUnits().length > 0) { /* Disable the firing of the selection event for a certain amount of time. This avoids firing many events if many units are selected */ if (!this.#selectionEventDisabled) { - getMap().setState(MOVE_UNIT); + getApp().getMap().setState(MOVE_UNIT); window.setTimeout(() => { document.dispatchEvent(new CustomEvent("unitsSelection", { detail: this.getSelectedUnits() })); this.#selectionEventDisabled = false; @@ -978,14 +978,14 @@ export class UnitsManager { } } else { - getMap().setState(IDLE); + getApp().getMap().setState(IDLE); document.dispatchEvent(new CustomEvent("clearSelection")); } } #onUnitDeselection(unit: Unit) { if (this.getSelectedUnits().length == 0) { - getMap().setState(IDLE); + getApp().getMap().setState(IDLE); document.dispatchEvent(new CustomEvent("clearSelection")); } else @@ -994,8 +994,8 @@ export class UnitsManager { #showActionMessage(units: Unit[], message: string) { if (units.length == 1) - getInfoPopup().setText(`${units[0].getUnitName()} ${message}`); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText(`${units[0].getUnitName()} ${message}`); else if (units.length > 1) - getInfoPopup().setText(`${units[0].getUnitName()} and ${units.length - 1} other units ${message}`); + (getApp().getPopupsManager().get("infoPopup") as Popup).setText(`${units[0].getUnitName()} and ${units.length - 1} other units ${message}`); } } \ No newline at end of file diff --git a/client/src/weapon/weapon.ts b/client/src/weapon/weapon.ts index 777afea3..139a1651 100644 --- a/client/src/weapon/weapon.ts +++ b/client/src/weapon/weapon.ts @@ -1,10 +1,9 @@ import { LatLng, DivIcon, Map } from 'leaflet'; -import { getMap, getMissionHandler, getUnitsManager } from '..'; +import { getApp } from '..'; import { enumToCoalition, mToFt, msToKnots, rad2deg } from '../other/utils'; import { CustomMarker } from '../map/markers/custommarker'; import { SVGInjector } from '@tanem/svg-injector'; import { DLINK, DataIndexes, GAME_MASTER, IRST, OPTIC, RADAR, VISUAL } from '../constants/constants'; -import { ObjectIconOptions } from '../@types/unit'; import { DataExtractor } from '../server/dataextractor'; export class Weapon extends CustomMarker { @@ -58,7 +57,7 @@ export class Weapon extends CustomMarker { /********************** Unit data *************************/ setData(dataExtractor: DataExtractor) { - var updateMarker = !getMap().hasLayer(this); + var updateMarker = !getApp().getMap().hasLayer(this); var datumIndex = 0; while (datumIndex != DataIndexes.endOfData) { @@ -116,7 +115,7 @@ export class Weapon extends CustomMarker { } belongsToCommandedCoalition() { - if (getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER && getMissionHandler().getCommandedCoalition() !== this.#coalition) + if (getApp().getMissionManager().getCommandModeOptions().commandMode !== GAME_MASTER && getApp().getMissionManager().getCommandedCoalition() !== this.#coalition) return false; return true; } @@ -166,7 +165,7 @@ export class Weapon extends CustomMarker { /********************** Visibility *************************/ updateVisibility() { - const hiddenUnits = getMap().getHiddenTypes(); + const hiddenUnits = getApp().getMap().getHiddenTypes(); var hidden = (hiddenUnits.includes(this.getMarkerCategory())) || (hiddenUnits.includes(this.#coalition)) || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0); @@ -178,16 +177,16 @@ export class Weapon extends CustomMarker { this.#hidden = hidden; /* Add the marker if not present */ - if (!getMap().hasLayer(this) && !this.getHidden()) { - if (getMap().isZooming()) - this.once("zoomend", () => {this.addTo(getMap())}) + if (!getApp().getMap().hasLayer(this) && !this.getHidden()) { + if (getApp().getMap().isZooming()) + this.once("zoomend", () => {this.addTo(getApp().getMap())}) else - this.addTo(getMap()); + this.addTo(getApp().getMap()); } /* Hide the marker if necessary*/ - if (getMap().hasLayer(this) && this.getHidden()) { - getMap().removeLayer(this); + if (getApp().getMap().hasLayer(this) && this.getHidden()) { + getApp().getMap().removeLayer(this); } } @@ -250,7 +249,7 @@ export class Weapon extends CustomMarker { } /* Set vertical offset for altitude stacking */ - var pos = getMap().latLngToLayerPoint(this.getLatLng()).round(); + var pos = getApp().getMap().latLngToLayerPoint(this.getLatLng()).round(); this.setZIndexOffset(1000 + Math.floor(this.#position.alt as number) - pos.y); } } diff --git a/client/src/weapon/weaponsmanager.ts b/client/src/weapon/weaponsmanager.ts index 57b6e48d..4de95b38 100644 --- a/client/src/weapon/weaponsmanager.ts +++ b/client/src/weapon/weaponsmanager.ts @@ -1,8 +1,7 @@ -import { getMissionHandler, getUnitsManager } from ".."; +import { getApp } from ".."; import { Weapon } from "./weapon"; import { DataIndexes, GAME_MASTER } from "../constants/constants"; import { DataExtractor } from "../server/dataextractor"; -import { Contact } from "../@types/unit"; /** The WeaponsManager handles the creation and update of weapons. Data is strictly updated by the server ONLY. */ export class WeaponsManager { @@ -93,7 +92,7 @@ export class WeaponsManager { */ getWeaponDetectedMethods(weapon: Weapon) { var detectionMethods: number[] = []; - var units = getUnitsManager().getUnits(); + var units = getApp().getUnitsManager().getUnits(); for (let idx in units) { if (units[idx].getAlive() && units[idx].getIsLeader() && units[idx].getCoalition() !== "neutral" && units[idx].getCoalition() != weapon.getCoalition()) { diff --git a/client/tsconfig.json b/client/tsconfig.json index c293f5f2..63da637e 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -23,19 +23,22 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ "module": "commonjs", /* Specify what module code is generated. */ - "rootDir": "./src", /* Specify the root folder within your source files. */ + "rootDirs": ["./src", "./@types"], /* Specify the root folder within your source files. */ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ "typeRoots": [ - "./node_modules/@types" + "./node_modules/@types", + "./@types" ], /* Specify multiple folders that act like './node_modules/@types'. */ "types": [ "leaflet", "geojson", "node", - "formatcoords" + "formatcoords", + "olympus", + "dom" ], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ @@ -100,6 +103,7 @@ "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, "include": [ - "src/**/*.ts" + "src/**/*.ts", + "@types/*.d.ts" ] } \ No newline at end of file diff --git a/client/views/aic/aic.ejs b/client/views/aic/aic.ejs deleted file mode 100644 index 229a5a82..00000000 --- a/client/views/aic/aic.ejs +++ /dev/null @@ -1,52 +0,0 @@ -
-
-
-
- -
-
×
-
AIC Help
-
-

How to be a good AIC and get people to do stuff good, too.

-
-
[DCS with Volvo video]
-
-
-
- -
- -
- -
-

My callsign

-
Magic
-
- -
- - -
- -
-

Control

-
- - -
-
- - -
-
- -
- -

Formations

- -
- -
- -
\ No newline at end of file diff --git a/client/views/atc/addflight.ejs b/client/views/atc/addflight.ejs deleted file mode 100644 index 97e1ae5b..00000000 --- a/client/views/atc/addflight.ejs +++ /dev/null @@ -1,5 +0,0 @@ -
-
- - -
\ No newline at end of file diff --git a/client/views/atc/atc.ejs b/client/views/atc/atc.ejs deleted file mode 100644 index 65984a3a..00000000 --- a/client/views/atc/atc.ejs +++ /dev/null @@ -1,11 +0,0 @@ -<%- include('board.ejs', { - "boardId": "strip-board-tower", - "boardType": "tower", - "headers": [ "Flight", "a. Alt", "alt", "a. Speed", "Speed" ] -}) %> - -<%- include('board.ejs', { - "boardId": "strip-board-ground", - "boardType": "ground", - "headers": [ "Flight", "Status", "T/O Time", "TTG" ] -}) %> \ No newline at end of file diff --git a/client/views/atc/board.ejs b/client/views/atc/board.ejs deleted file mode 100644 index 58d3dfcc..00000000 --- a/client/views/atc/board.ejs +++ /dev/null @@ -1,22 +0,0 @@ -
- -
- -
-

<%= boardType %>

- <%- include('addflight.ejs') %> -
-
- -
-
-
- <% headers.forEach( header => { %> -
<%= header %>
- <% }); %> -
-
-
-
- -
\ No newline at end of file diff --git a/client/views/atc/unitdatatable.ejs b/client/views/atc/unitdatatable.ejs deleted file mode 100644 index 0c090652..00000000 --- a/client/views/atc/unitdatatable.ejs +++ /dev/null @@ -1,13 +0,0 @@ -
- -
- -
-

Unit list

-
- -
- -
- -
\ No newline at end of file