From 5a828e976f7196f795cbb0f619134bc56a1fe342 Mon Sep 17 00:00:00 2001 From: Christophe TARET Date: Thu, 16 May 2024 09:25:14 +0200 Subject: [PATCH 01/20] feat: add an optimizer library, use it in flyxc front XC planning. This library computes scores for flights using applicable rules of various XC leagues. It permit computations with small chunks of time or cycles. Optimizer can send successive results that are not optimal. This can be useful to interrupt optimization properly if it is too long. --- CONTRIBUTING.md | 49 ++ .../src/app/components/2d/path-element.ts | 36 +- .../src/app/components/2d/planner-element.ts | 2 +- .../src/app/components/ui/pref-modal.ts | 2 +- apps/fxc-front/src/app/logic/score/league.ts | 7 - .../src/app/logic/score/league/czech.ts | 68 --- .../src/app/logic/score/league/frcfd.ts | 25 - .../src/app/logic/score/league/leagues.ts | 68 ++- .../src/app/logic/score/league/leonardo.ts | 21 - .../src/app/logic/score/league/ukxcl.ts | 153 ------ .../src/app/logic/score/league/wxc.ts | 20 - .../src/app/logic/score/league/xcontest.ts | 66 --- apps/fxc-front/src/app/logic/score/measure.ts | 153 ------ apps/fxc-front/src/app/logic/score/scorer.ts | 136 +----- apps/fxc-front/vite.config.ts | 2 + docker/.env | 2 + docker/docker-compose.yml | 25 + libs/optimizer/.babelrc | 3 + libs/optimizer/.eslintrc.json | 25 + libs/optimizer/README.md | 30 ++ libs/optimizer/jest.config.ts | 11 + libs/optimizer/project.json | 20 + libs/optimizer/src/index.ts | 10 + .../src/lib/fixtures/optimizer.fixtures.ts | 456 ++++++++++++++++++ libs/optimizer/src/lib/optimizer.spec.ts | 153 ++++++ libs/optimizer/src/lib/optimizer.ts | 335 +++++++++++++ libs/optimizer/src/lib/scoringRules.ts | 112 +++++ .../optimizer/src/lib/utils/createSegments.ts | 46 ++ libs/optimizer/src/lib/utils/mergeTracks.ts | 23 + libs/optimizer/tsconfig.json | 13 + libs/optimizer/tsconfig.lib.json | 10 + libs/optimizer/tsconfig.spec.json | 9 + nx.json | 5 + package-lock.json | 59 +++ package.json | 3 + tsconfig.base.json | 3 +- 36 files changed, 1490 insertions(+), 671 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 apps/fxc-front/src/app/logic/score/league.ts delete mode 100644 apps/fxc-front/src/app/logic/score/league/czech.ts delete mode 100644 apps/fxc-front/src/app/logic/score/league/frcfd.ts delete mode 100644 apps/fxc-front/src/app/logic/score/league/leonardo.ts delete mode 100644 apps/fxc-front/src/app/logic/score/league/ukxcl.ts delete mode 100644 apps/fxc-front/src/app/logic/score/league/wxc.ts delete mode 100644 apps/fxc-front/src/app/logic/score/league/xcontest.ts delete mode 100644 apps/fxc-front/src/app/logic/score/measure.ts create mode 100644 docker/.env create mode 100644 docker/docker-compose.yml create mode 100644 libs/optimizer/.babelrc create mode 100644 libs/optimizer/.eslintrc.json create mode 100644 libs/optimizer/README.md create mode 100644 libs/optimizer/jest.config.ts create mode 100644 libs/optimizer/project.json create mode 100644 libs/optimizer/src/index.ts create mode 100644 libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts create mode 100644 libs/optimizer/src/lib/optimizer.spec.ts create mode 100644 libs/optimizer/src/lib/optimizer.ts create mode 100644 libs/optimizer/src/lib/scoringRules.ts create mode 100644 libs/optimizer/src/lib/utils/createSegments.ts create mode 100644 libs/optimizer/src/lib/utils/mergeTracks.ts create mode 100644 libs/optimizer/tsconfig.json create mode 100644 libs/optimizer/tsconfig.lib.json create mode 100644 libs/optimizer/tsconfig.spec.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..4c476100 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,49 @@ +# How to contribute. + +## Required tools + +- node.js +- npm +- on mac-os, you have to install xcode command line developer tools (run xcode-select --install) +- gcloud +- docker +- the IDE of your choice + +## Project setup + +- run `npm install` +- add default keys definitions + - `cp apps/fxc-front/src/app/keys.ts.dist apps/fxc-front/src/app/keys.ts` + - `cp libs/common/src/lib/keys.ts.dist libs/common/src/lib/keys.ts` + +### Simplistic configuration + +**redis server** + +- `cd docker; docker compose up -d redis` + +**pubsub** + +- `cd docker; docker compose up -d pubsub` + +**datastore** + +For the moment, it does not work with docker compose. But if you install the cloud-datastore-emulator, you will have a working configuration. + +**_Installation_** + +- `gcloud components install cloud-datastore-emulator` + +**_run the data store:_** + +- `gcloud beta emulators datastore start --data-dir=MY_DATA_DIR` + +**_before npm run dev:_** + +- open another shell. +- define the required environment variables:`eval $(gcloud beta emulators datastore --data-dir=MY_DATA_DIR env-init)` +- you can then run the application locally in this shell with `npm run dev` + +## Before you submit your PR: + +run this command to format/lint/test: `npx nx check` diff --git a/apps/fxc-front/src/app/components/2d/path-element.ts b/apps/fxc-front/src/app/components/2d/path-element.ts index 4ad48940..7a7cd1f6 100644 --- a/apps/fxc-front/src/app/components/2d/path-element.ts +++ b/apps/fxc-front/src/app/components/2d/path-element.ts @@ -13,12 +13,12 @@ import { FaiSectors } from '../../gm/fai-sectors'; import { addAltitude } from '../../logic/elevation'; import { getCurrentUrl, pushCurrentState } from '../../logic/history'; import { drawRoute } from '../../logic/messages'; -import { LEAGUES } from '../../logic/score/league/leagues'; -import { Measure } from '../../logic/score/measure'; import { CircuitType, Score } from '../../logic/score/scorer'; import { setDistance, setEnabled, setRoute, setScore } from '../../redux/planner-slice'; import { RootState, store } from '../../redux/store'; import { PlannerElement } from './planner-element'; +import { getOptimizer, ScoringTrack } from '@flyxc/optimizer'; +import { getScoringRules } from '../../logic/score/league/leagues'; // Route color by circuit type. const ROUTE_STROKE_COLORS = { @@ -191,18 +191,14 @@ export class PathElement extends connect(store)(LitElement) { // Optimize the route and draw the optimize lines and sectors. private optimize(): void { - if (!this.line || this.line.getPath().getLength() < 2) { + if (!this.line || this.line.getPath().getLength() < 2 || this.doNotSyncState) { return; } const line = this.line; store.dispatch(setDistance(google.maps.geometry.spherical.computeLength(line.getPath()))); const points = this.getPathPoints(); - const measure = new Measure(points); - const scores = LEAGUES[this.league].score(measure); - - scores.sort((score1, score2) => score2.points - score1.points); - const score = scores[0]; + const score = this.computeScore(points); store.dispatch(setScore(score)); let optimizedPath = score.indexes.map((index) => new google.maps.LatLng(points[index].lat, points[index].lon)); @@ -229,10 +225,10 @@ export class PathElement extends connect(store)(LitElement) { this.closingSector.addListener('rightclick', (e) => this.appendToPath(e.latLng)); } - if (score.closingRadius) { + if (score.closingRadiusM) { const center = points[score.indexes[0]]; this.closingSector.center = center; - this.closingSector.radius = score.closingRadius; + this.closingSector.radius = score.closingRadiusM; this.closingSector.update(); this.closingSector.setMap(this.map); } else { @@ -254,12 +250,28 @@ export class PathElement extends connect(store)(LitElement) { this.postScoreToHost(score); } + private computeScore(points: LatLon[]): Score { + const track: ScoringTrack = { + points: points.map((point, i) => ({ ...point, alt: 0, timeSec: i * 60 })), + startTimeSec: Math.round(new Date().getTime() / 1000), + }; + const result = getOptimizer({ track }, getScoringRules(this.league)).next().value; + return new Score({ + circuit: result.circuit, + distanceM: result.lengthKm * 1000, + multiplier: result.multiplier, + closingRadiusM: result.closingRadius ? result.closingRadius * 1000 : null, + indexes: result.solutionIndices, + points: result.score, + }); + } + // Sends a message to the iframe host with the changes. private postScoreToHost(score: Score) { let kms = ''; let circuit = ''; - if (score.distance && window.parent) { - kms = (score.distance / 1000).toFixed(1); + if (score.distanceM && window.parent) { + kms = (score.distanceM / 1000).toFixed(1); circuit = CIRCUIT_SHORT_NAME[score.circuit]; if (score.circuit == CircuitType.OpenDistance) { circuit += score.indexes.length - 2; diff --git a/apps/fxc-front/src/app/components/2d/planner-element.ts b/apps/fxc-front/src/app/components/2d/planner-element.ts index 270c5a8e..65ca3958 100644 --- a/apps/fxc-front/src/app/components/2d/planner-element.ts +++ b/apps/fxc-front/src/app/components/2d/planner-element.ts @@ -139,7 +139,7 @@ export class PlannerElement extends connect(store)(LitElement) {
${this.score.circuit}
- ${unsafeHTML(units.formatUnit(this.score.distance / 1000, this.units.distance, undefined, 'unit'))} + ${unsafeHTML(units.formatUnit(this.score.distanceM / 1000, this.units.distance, undefined, 'unit'))}
diff --git a/apps/fxc-front/src/app/components/ui/pref-modal.ts b/apps/fxc-front/src/app/components/ui/pref-modal.ts index fa3e1db0..d544e3ca 100644 --- a/apps/fxc-front/src/app/components/ui/pref-modal.ts +++ b/apps/fxc-front/src/app/components/ui/pref-modal.ts @@ -22,7 +22,7 @@ export class PrefModal extends connect(store)(LitElement) { constructor() { super(); Object.getOwnPropertyNames(LEAGUES).forEach((value) => { - this.leagues.push({ value, name: LEAGUES[value].name }); + this.leagues.push({ value, name: LEAGUES[value] }); }); this.leagues.sort((a, b) => (a < b ? -1 : 1)); } diff --git a/apps/fxc-front/src/app/logic/score/league.ts b/apps/fxc-front/src/app/logic/score/league.ts deleted file mode 100644 index b13c7777..00000000 --- a/apps/fxc-front/src/app/logic/score/league.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Measure } from './measure'; -import { Score } from './scorer'; - -export abstract class League { - abstract name: string; - abstract score(measure: Measure): Score[]; -} diff --git a/apps/fxc-front/src/app/logic/score/league/czech.ts b/apps/fxc-front/src/app/logic/score/league/czech.ts deleted file mode 100644 index 53a9350d..00000000 --- a/apps/fxc-front/src/app/logic/score/league/czech.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Measure } from '../measure'; -import { Score, scoreCircuits, scoreOpenDistance, scoreTriangles } from '../scorer'; - -abstract class CZXCBase { - score(measure: Measure): Score[] { - return [ - ...scoreOpenDistance(measure, 3, this.openDistanceMultiplier), - ...scoreCircuits(measure, null, this.scoreTriangles), - ]; - } - protected scoreTriangles = (measure: Measure, distances: number[], indexes: number[]): Score[] => - scoreTriangles( - this.flatTriangleMultiplier(), - this.faiTriangleMultiplier(), - 0.05, - false, - true, - measure, - distances, - indexes, - ); - - protected abstract faiTriangleMultiplier(): number; - protected abstract flatTriangleMultiplier(): number; - protected abstract openDistanceMultiplier(): number; -} - -export class CzechLocal extends CZXCBase { - name = 'Czech (ČPP local)'; - - protected faiTriangleMultiplier(): number { - return 2.2; - } - protected flatTriangleMultiplier(): number { - return 1.8; - } - protected openDistanceMultiplier(): number { - return 1; - } -} - -export class CzechEurope extends CZXCBase { - name = 'Czech (ČPP Europe)'; - - protected faiTriangleMultiplier(): number { - return 1.4; - } - protected flatTriangleMultiplier(): number { - return 1.2; - } - protected openDistanceMultiplier(): number { - return 1; - } -} - -export class CzechOutEurope extends CZXCBase { - name = 'Czech (ČPP outside Europe)'; - - protected faiTriangleMultiplier(): number { - return 1.4; - } - protected flatTriangleMultiplier(): number { - return 1.2; - } - protected openDistanceMultiplier(): number { - return 0.8; - } -} diff --git a/apps/fxc-front/src/app/logic/score/league/frcfd.ts b/apps/fxc-front/src/app/logic/score/league/frcfd.ts deleted file mode 100644 index 993281c5..00000000 --- a/apps/fxc-front/src/app/logic/score/league/frcfd.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { League } from '../league'; -import { Measure } from '../measure'; -import { Score, scoreCircuits, scoreOpenDistance, scoreTriangles } from '../scorer'; - -export class FrCfd extends League { - name = 'France (CFD)'; - - score(measure: Measure): Score[] { - return [ - ...scoreOpenDistance(measure, 3, this.openDistanceMultiplier), - ...scoreCircuits(measure, null, this.scoreTriangleAbsolute), - ...scoreCircuits(measure, null, this.scoreTriangleRelative), - ]; - } - - protected scoreTriangleRelative = (measure: Measure, distances: number[], indexes: number[]): Score[] => - scoreTriangles(1.2, 1.4, 0.05, false, true, measure, distances, indexes); - - protected scoreTriangleAbsolute = (measure: Measure, distances: number[], indexes: number[]): Score[] => - scoreTriangles(1.2, 1.4, 3000, true, false, measure, distances, indexes); - - protected openDistanceMultiplier(distance: number): number { - return distance < 15000 ? 0 : 1; - } -} diff --git a/apps/fxc-front/src/app/logic/score/league/leagues.ts b/apps/fxc-front/src/app/logic/score/league/leagues.ts index 19fab934..f94f05ed 100644 --- a/apps/fxc-front/src/app/logic/score/league/leagues.ts +++ b/apps/fxc-front/src/app/logic/score/league/leagues.ts @@ -1,22 +1,50 @@ -import { League } from '../league'; -import { CzechEurope, CzechLocal, CzechOutEurope } from './czech'; -import { FrCfd } from './frcfd'; -import { Leonardo } from './leonardo'; -import { UKXCLClub, UKXCLInternational, UKXCLNational } from './ukxcl'; -import { WXC } from './wxc'; -import { NorwayLeague, XContest, XContestPPG } from './xcontest'; +import { ScoringRules } from '@flyxc/optimizer'; -export const LEAGUES: { [name: string]: League } = { - czl: new CzechLocal(), - cze: new CzechEurope(), - czo: new CzechOutEurope(), - fr: new FrCfd(), - leo: new Leonardo(), - nor: new NorwayLeague(), - ukc: new UKXCLClub(), - uki: new UKXCLInternational(), - ukn: new UKXCLNational(), - xc: new XContest(), - xcppg: new XContestPPG(), - wxc: new WXC(), +// allowed league codes +export const leagueCodes = ['czl', 'cze', 'czo', 'fr', 'leo', 'nor', 'ukc', 'uki', 'ukn', 'xc', 'xcppg', 'wxc']; +export type LeagueCode = (typeof leagueCodes)[number]; + +export const LEAGUES: Readonly> = { + czl: 'Czech (ČPP local)', + cze: 'Czech (ČPP Europe)', + czo: 'Czech (ČPP outside Europe)', + fr: 'France (CFD)', + leo: 'Leonardo', + nor: 'Norway (Distanseligaen)', + ukc: 'UK (XC League, Club)', + uki: 'UK (XC League, International)', + ukn: 'UK (XC League, National)', + xc: 'XContest', + xcppg: 'XContest PPG', + wxc: 'World XC Online Contest', }; + +export function getScoringRules(league: LeagueCode): ScoringRules { + switch (league) { + case 'czl': + return 'CzechLocal'; + case 'cze': + return 'CzechEuropean'; + case 'czo': + return 'CzechOutsideEurope'; + case 'fr': + return 'FederationFrancaiseVolLibre'; + case 'leo': + return 'Leonardo'; + case 'nor': + return 'Norway'; + case 'ukc': + return 'UnitedKingdomClub'; + case 'uki': + return 'UnitedKingdomInternational'; + case 'ukn': + return 'UnitedKingdomNational'; + case 'xc': + return 'XContest'; + case 'xcppg': + return 'XContestPPG'; + case 'wxc': + return 'WorldXC'; + } + throw Error('no corresponding rule for ' + league); +} diff --git a/apps/fxc-front/src/app/logic/score/league/leonardo.ts b/apps/fxc-front/src/app/logic/score/league/leonardo.ts deleted file mode 100644 index 00a65dec..00000000 --- a/apps/fxc-front/src/app/logic/score/league/leonardo.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { League } from '../league'; -import { Measure } from '../measure'; -import { Score, scoreCircuits, scoreOpenDistance, scoreTriangles } from '../scorer'; - -export class Leonardo extends League { - name = 'Leonardo'; - - score(measure: Measure): Score[] { - return [ - ...scoreOpenDistance(measure, 3, this.openDistanceMultiplier), - ...scoreCircuits(measure, null, this.scoreTriangles), - ]; - } - - protected scoreTriangles = (measure: Measure, distances: number[], indexes: number[]): Score[] => - scoreTriangles(1.75, 2, 0.2, false, true, measure, distances, indexes); - - protected openDistanceMultiplier(): number { - return 1.5; - } -} diff --git a/apps/fxc-front/src/app/logic/score/league/ukxcl.ts b/apps/fxc-front/src/app/logic/score/league/ukxcl.ts deleted file mode 100644 index 662bb27c..00000000 --- a/apps/fxc-front/src/app/logic/score/league/ukxcl.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { Measure } from '../measure'; -import { CircuitType, Score, scoreCircuits, scoreOpenDistance } from '../scorer'; - -function scoreOutAndReturn(multiplierFn: (d: number) => number, measure: Measure): Score[] { - let maxIndexes; - let maxDistance = 0; - let maxScoringDistance = 0; - const len = measure.points.length; - for (let i = 0; i < len - 1; i++) { - for (let tp1 = i; tp1 < len - 1; tp1++) { - for (let tp2 = tp1 + 1; tp2 < len; tp2++) { - const distance = measure.getDistance(tp1, tp2); - for (let l = tp2; l < len; l++) { - const gap = measure.getDistance(i, l); - if (gap <= 800) { - const scoringDistance = 2 * distance - gap; - if (scoringDistance > maxScoringDistance) { - maxIndexes = [i, tp1, tp2, l]; - maxDistance = distance; - maxScoringDistance = scoringDistance; - } - } - } - } - } - } - return maxIndexes == null - ? [] - : [ - new Score({ - distance: maxScoringDistance, - indexes: maxIndexes, - multiplier: multiplierFn(2 * maxDistance), - circuit: CircuitType.OutAndReturn, - closingRadius: 800, - }), - ]; -} - -function scoreTriangles( - faiMultiplierFn: (d: number) => number, - flatMultiplierFn: (d: number) => number, - measure: Measure, - distances: number[], - indexes: number[], -): Score[] { - const firstIndex = indexes[0]; - const lastIndex = indexes[2]; - const len = measure.points.length; - const distance = distances[0] + distances[1] + distances[2]; - const shortestLegFraction = Math.min(...distances) / distance; - const longestLegFraction = Math.max(...distances) / distance; - let multiplier; - let circuit; - if (shortestLegFraction >= 0.28) { - multiplier = faiMultiplierFn(distance); - circuit = CircuitType.FaiTriangle; - } else if (shortestLegFraction >= 0.15 && longestLegFraction <= 0.45) { - multiplier = flatMultiplierFn(distance); - circuit = CircuitType.FlatTriangle; - } else { - return []; - } - let minGap = 800; - let minIndexes; - for (let i = firstIndex; i >= 0; --i) { - for (let j = lastIndex; j < len; ++j) { - const gap = measure.getDistance(i, j); - if (gap < minGap) { - minGap = gap; - minIndexes = [i, ...indexes, j]; - } - } - } - return minIndexes == null - ? [] - : [ - new Score({ - distance: distance - minGap, - indexes: minIndexes, - multiplier, - circuit, - closingRadius: 800, - }), - ]; -} - -abstract class UKXCLBase { - score(measure: Measure): Score[] { - return [ - ...scoreOpenDistance(measure, 3, this.openDistanceMultiplier), - ...scoreCircuits(measure, this.scoreOutAndReturn, this.scoreTriangles), - ]; - } - - protected abstract outAndReturnFlatTriangleMultiplier(distance: number): number; - protected abstract faiTriangleMultiplier(distance: number): number; - protected abstract openDistanceMultiplier(distance: number): number; - - protected scoreOutAndReturn = (measure: Measure): Score[] => - scoreOutAndReturn(this.outAndReturnFlatTriangleMultiplier, measure); - - protected scoreTriangles = (measure: Measure, distances: number[], indexes: number[]): Score[] => - scoreTriangles(this.faiTriangleMultiplier, this.outAndReturnFlatTriangleMultiplier, measure, distances, indexes); -} - -export class UKXCLClub extends UKXCLBase { - name = 'UK (XC League, Club)'; - - protected outAndReturnFlatTriangleMultiplier(distance: number): number { - return distance < 5000 ? 0 : distance < 15000 ? 1.2 : distance < 35000 ? 1.3 : 1.7; - } - - protected faiTriangleMultiplier(distance: number): number { - return distance < 5000 ? 0 : distance < 15000 ? 1.5 : distance < 35000 ? 1.7 : 2.0; - } - - protected openDistanceMultiplier(distance: number): number { - return distance < 5000 ? 0 : 1; - } -} - -export class UKXCLInternational extends UKXCLBase { - name = 'UK (XC League, International)'; - - protected outAndReturnFlatTriangleMultiplier(distance: number): number { - return distance < 35000 ? 0 : 1.2; - } - - protected faiTriangleMultiplier(distance: number): number { - return distance < 25000 ? 0 : 1.5; - } - - protected openDistanceMultiplier(distance: number): number { - return distance < 10000 ? 0 : 1; - } -} - -export class UKXCLNational extends UKXCLBase { - name = 'UK (XC League, National)'; - - protected outAndReturnFlatTriangleMultiplier(distance: number): number { - return distance < 15000 ? 0 : distance < 35000 ? 1.3 : 1.7; - } - - protected faiTriangleMultiplier(distance: number): number { - return distance < 15000 ? 0 : distance < 25000 ? 1.7 : 2.0; - } - - protected openDistanceMultiplier(distance: number): number { - return distance < 10000 ? 0 : 1; - } -} diff --git a/apps/fxc-front/src/app/logic/score/league/wxc.ts b/apps/fxc-front/src/app/logic/score/league/wxc.ts deleted file mode 100644 index a3671cde..00000000 --- a/apps/fxc-front/src/app/logic/score/league/wxc.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Measure } from '../measure'; -import { Score, scoreCircuits, scoreOpenDistance, scoreTriangles } from '../scorer'; - -export class WXC { - name = 'World XC Online Contest'; - - score(measure: Measure): Score[] { - return [ - ...scoreOpenDistance(measure, 3, this.openDistanceMultiplier), - ...scoreCircuits(measure, null, this.scoreTriangles), - ]; - } - - protected scoreTriangles = (measure: Measure, distances: number[], indexes: number[]): Score[] => - scoreTriangles(1.75, 2, 0.2, false, true, measure, distances, indexes); - - protected openDistanceMultiplier(): number { - return 1; - } -} diff --git a/apps/fxc-front/src/app/logic/score/league/xcontest.ts b/apps/fxc-front/src/app/logic/score/league/xcontest.ts deleted file mode 100644 index 8e5ee30f..00000000 --- a/apps/fxc-front/src/app/logic/score/league/xcontest.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Measure } from '../measure'; -import { Score, scoreCircuits, ScoreFunction, scoreOpenDistance, scoreTriangles } from '../scorer'; - -// https://www.xcontest.org/world/en/rules/ -export class XContest { - name = 'XContest'; - - score(measure: Measure): Score[] { - return [ - ...scoreOpenDistance(measure, 3, this.openDistanceMultiplier), - ...scoreCircuits(measure, null, this.scoreTriangles1), - ...scoreCircuits(measure, null, this.scoreTriangles2), - ]; - } - - protected scoreTriangles1: ScoreFunction = (measure: Measure, distances: number[], indexes: number[]): Score[] => - scoreTriangles(1.4, 1.6, 0.05, false, true, measure, distances, indexes); - - protected scoreTriangles2 = (measure: Measure, distances: number[], indexes: number[]): Score[] => - scoreTriangles(1.2, 1.4, 0.2, false, true, measure, distances, indexes); - - protected openDistanceMultiplier(): number { - return 1; - } -} - -// https://paramotors.xcontest.org/world/en/rules/ -export class XContestPPG { - name = 'XContest PPG'; - - score(measure: Measure): Score[] { - return [ - ...scoreOpenDistance(measure, 3, this.openDistanceMultiplier), - ...scoreCircuits(measure, null, this.scoreTriangles1), - ]; - } - - protected scoreTriangles1: ScoreFunction = (measure: Measure, distances: number[], indexes: number[]): Score[] => - scoreTriangles(2.0, 4.0, 800, true, true, measure, distances, indexes); - - protected openDistanceMultiplier(): number { - return 1; - } -} - -export class NorwayLeague { - name = 'Norway (Distanseligaen)'; - - score(measure: Measure): Score[] { - return [ - ...scoreOpenDistance(measure, 3, this.openDistanceMultiplier), - ...scoreCircuits(measure, null, this.scoreTriangles1), - ...scoreCircuits(measure, null, this.scoreTriangles2), - ]; - } - - protected scoreTriangles1: ScoreFunction = (measure: Measure, distances: number[], indexes: number[]): Score[] => - scoreTriangles(1.7, 2.4, 0.05, false, true, measure, distances, indexes); - - protected scoreTriangles2 = (measure: Measure, distances: number[], indexes: number[]): Score[] => - scoreTriangles(1.5, 2.2, 0.2, false, true, measure, distances, indexes); - - protected openDistanceMultiplier(): number { - return 1; - } -} diff --git a/apps/fxc-front/src/app/logic/score/measure.ts b/apps/fxc-front/src/app/logic/score/measure.ts deleted file mode 100644 index 541c8a98..00000000 --- a/apps/fxc-front/src/app/logic/score/measure.ts +++ /dev/null @@ -1,153 +0,0 @@ -// Optimization code adapted from -// https://github.com/twpayne/maxxc/blob/7c22a46536ec7299ec91d135fea10b5b5925032c/track.c - -import { LatLon } from '@flyxc/common'; -import { getDistance } from 'geolib'; - -export interface PointReference { - index: number; - distance: number; -} - -export class Measure { - private maxDelta = 0; - private len: number; - private distanceCache: { [idxA: number]: { [idxB: number]: number } } = {}; - private farthestBefore: PointReference[] = []; - private farthestAfter: PointReference[] = []; - - constructor(public points: LatLon[]) { - this.len = points.length; - for (let i = 0; i < this.len - 1; i++) { - this.maxDelta = Math.max(this.maxDelta, getDistance(points[i], points[i + 1])); - } - this.farthestBefore.push({ index: 0, distance: 0 }); - for (let i = 1; i < this.len; i++) { - this.farthestBefore.push(this.getFarthestFrom(i, 0, i, 0)); - } - for (let i = 0; i < this.len - 1; i++) { - this.farthestAfter.push(this.getFarthestFrom(i, i, this.len, 0)); - } - this.farthestAfter.push({ index: this.len - 1, distance: 0 }); - } - - getDistance(indexA: number, indexB: number): number { - if (indexA === indexB) { - return 0; - } - if (indexB < indexA) { - [indexA, indexB] = [indexB, indexA]; - } - if (!(indexA in this.distanceCache)) { - this.distanceCache[indexA] = {}; - } - if (!(indexB in this.distanceCache[indexA])) { - this.distanceCache[indexA][indexB] = getDistance(this.points[indexA], this.points[indexB]); - } - return this.distanceCache[indexA][indexB]; - } - - getFarthestFrom(ref: number, startIndex: number, stopIndex: number, bound: number): PointReference { - let index = -1; - let distance; - for (let i = startIndex; i < stopIndex; ) { - distance = this.getDistance(ref, i); - if (distance >= bound) { - index = i; - bound = distance; - i++; - } else { - i = this.fastForward(i, bound - distance); - } - } - return { index, distance: bound }; - } - - computeOpenDistance0(): { distance: number; indexes: number[] } { - const indexes = [-1, -1]; - let bound = -1; - for (let start = 0; start < this.len - 1; start++) { - const finish = this.getFarthestFrom(start, start + 1, this.len, bound); - if (finish.index > -1) { - indexes[0] = start; - indexes[1] = finish.index; - bound = finish.distance; - } - } - return { distance: bound, indexes }; - } - - computeOpenDistance1(): { distance: number; indexes: number[] } { - const indexes = [-1, -1, -1]; - let bound = -1; - for (let tp1 = 1; tp1 < this.len - 1; ) { - const total = this.farthestBefore[tp1].distance + this.farthestAfter[tp1].distance; - if (total > bound) { - indexes[0] = this.farthestBefore[tp1].index; - indexes[1] = tp1; - indexes[2] = this.farthestAfter[tp1].index; - bound = total; - tp1++; - } else { - tp1 = this.fastForward(tp1, (bound - total) / 2); - } - } - return { distance: bound, indexes }; - } - - computeOpenDistance2(): { distance: number; indexes: number[] } { - const indexes = [-1, -1, -1, -1]; - let bound = -1; - for (let tp1 = 1; tp1 < this.len - 2; tp1++) { - const leg1 = this.farthestBefore[tp1].distance; - for (let tp2 = tp1 + 1; tp2 < this.len - 1; ) { - const distance = leg1 + this.getDistance(tp1, tp2) + this.farthestAfter[tp2].distance; - if (distance > bound) { - indexes[0] = this.farthestBefore[tp1].index; - indexes[1] = tp1; - indexes[2] = tp2; - indexes[3] = this.farthestAfter[tp2].index; - bound = distance; - tp2++; - } else { - tp2 = this.fastForward(tp2, (bound - distance) / 2); - } - } - } - return { distance: bound, indexes }; - } - - computeOpenDistance3(): { distance: number; indexes: number[] } { - const indexes = [-1, -1, -1, -1, -1]; - let bound = -1; - for (let tp1 = 1; tp1 < this.len - 3; tp1++) { - const leg1 = this.farthestBefore[tp1].distance; - for (let tp2 = tp1 + 1; tp2 < this.len - 2; tp2++) { - const leg2 = this.getDistance(tp1, tp2); - for (let tp3 = tp2 + 1; tp3 < this.len - 1; ) { - const distance = leg1 + leg2 + this.getDistance(tp2, tp3) + this.farthestAfter[tp3].distance; - if (distance > bound) { - indexes[0] = this.farthestBefore[tp1].index; - indexes[1] = tp1; - indexes[2] = tp2; - indexes[3] = tp3; - indexes[4] = this.farthestAfter[tp3].index; - bound = distance; - tp3++; - } else { - tp3 = this.fastForward(tp3, (bound - distance) / 2); - } - } - } - } - return { distance: bound, indexes }; - } - - private fastForward(index: number, distance: number): number { - if (this.maxDelta == 0) { - return index + 1; - } - const step = Math.floor(distance / this.maxDelta); - return index + Math.max(step, 1); - } -} diff --git a/apps/fxc-front/src/app/logic/score/scorer.ts b/apps/fxc-front/src/app/logic/score/scorer.ts index 89269756..488b7fcc 100644 --- a/apps/fxc-front/src/app/logic/score/scorer.ts +++ b/apps/fxc-front/src/app/logic/score/scorer.ts @@ -1,6 +1,4 @@ -import { Measure } from './measure'; - -export type ScoreFunction = (measure: Measure, distances: number[], indexes: number[]) => Score[]; +import { CircuitType as OptimizerCircuitType } from '@flyxc/optimizer'; export enum CircuitType { OpenDistance = 'Open distance', @@ -9,132 +7,24 @@ export enum CircuitType { OutAndReturn = 'Out and return', } +export function getCircuitType(circuit?: OptimizerCircuitType) { + return circuit as unknown as CircuitType; +} + export class Score { - distance: number; + distanceM: number; indexes: number[]; multiplier: number; circuit: CircuitType; - closingRadius: number | null; + closingRadiusM: number | null; points: number; constructor(score: Partial) { - this.distance = score.distance || 0; - this.indexes = score.indexes || []; - this.multiplier = score.multiplier || 1; - this.circuit = score.circuit || CircuitType.OpenDistance; - this.closingRadius = score.closingRadius || null; - this.points = (this.distance * this.multiplier) / 1000; - } -} - -export function scoreOpenDistance( - measure: Measure, - maxTurnpoints: number, - multiplierFn: (d: number) => number, -): Score[] { - const len = measure.points.length; - let result: any; - if (maxTurnpoints == 0 || len == 2) { - result = measure.computeOpenDistance0(); - } else if (maxTurnpoints == 1 || len == 3) { - result = measure.computeOpenDistance1(); - } else if (maxTurnpoints == 2 || len == 4) { - result = measure.computeOpenDistance2(); - } else if (maxTurnpoints == 3 || len == 5) { - result = measure.computeOpenDistance3(); - } - - return result - ? [ - new Score({ - distance: result.distance, - indexes: result.indexes, - multiplier: multiplierFn(result.distance), - circuit: CircuitType.OpenDistance, - }), - ] - : []; -} - -export function scoreCircuits( - measure: Measure, - scoreOutAndReturn: ScoreFunction | null, - scoreTriangles: ScoreFunction | null, -): Score[] { - const len = measure.points.length; - const distances = [0, 0, 0]; - const scores: Score[] = []; - for (let i = 0; i < len - 2; i++) { - for (let j = i + 1; j < len - 1; j++) { - distances[0] = measure.getDistance(i, j); - if (scoreOutAndReturn) { - const score = scoreOutAndReturn(measure, distances, [i, j]); - if (score) { - scores.push(...score); - } - } - if (scoreTriangles) { - for (let k = j + 1; k < len; k++) { - distances[1] = measure.getDistance(j, k); - distances[2] = measure.getDistance(k, i); - const score = scoreTriangles(measure, distances, [i, j, k]); - if (score) { - scores.push(...score); - } - } - } - } - } - return scores; -} - -export function scoreTriangles( - flatMul: number | undefined, - faiMul: number | undefined, - tolerance: number, - absolute: boolean, - penalize: boolean, - measure: Measure, - distances: number[], - indexes: number[], -): Score[] { - const firstIdx = indexes[0]; - const lastIdx = indexes[2]; - const len = measure.points.length; - const distance = distances[0] + distances[1] + distances[2]; - const closingRadius = absolute ? tolerance : tolerance * distance; - let minGap = closingRadius; - let minIndexes: null | number[] = null; - for (let i = firstIdx; i >= 0; i--) { - for (let j = lastIdx; j < len; j++) { - const gap = measure.getDistance(i, j); - if (gap <= minGap) { - minGap = gap; - minIndexes = [i, ...indexes, j]; - } - } - } - if (!minIndexes) { - return []; - } - let multiplier: number; - let circuit: CircuitType; - if (faiMul && Math.min(...distances) / distance >= 0.28) { - multiplier = faiMul; - circuit = CircuitType.FaiTriangle; - } else if (flatMul) { - multiplier = flatMul; - circuit = CircuitType.FlatTriangle; - } else { - return []; + this.distanceM = score.distanceM ?? 0; + this.indexes = score.indexes ?? []; + this.multiplier = score.multiplier ?? 1; + this.circuit = score.circuit ?? CircuitType.OpenDistance; + this.closingRadiusM = score.closingRadiusM ?? null; + this.points = score.points ?? 0; } - return [ - new Score({ - distance: penalize ? distance - minGap : distance, - indexes: minIndexes, - multiplier, - circuit, - closingRadius, - }), - ]; } diff --git a/apps/fxc-front/vite.config.ts b/apps/fxc-front/vite.config.ts index 488ba723..fec8334f 100644 --- a/apps/fxc-front/vite.config.ts +++ b/apps/fxc-front/vite.config.ts @@ -93,6 +93,8 @@ export default defineConfig({ define: { __BUILD_TIMESTAMP__: JSON.stringify(format(new Date(), 'yyyyMMdd.HHmm')), __AIRSPACE_DATE__: JSON.stringify(getAirspaceDate()), + // required by igc-xc-score. TODO(vicb): check how to remove this + global: {}, }, }); diff --git a/docker/.env b/docker/.env new file mode 100644 index 00000000..ba9867c0 --- /dev/null +++ b/docker/.env @@ -0,0 +1,2 @@ +# docker compose env file +COMPOSE_PROJECT_NAME=flyxc diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 00000000..9945240f --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,25 @@ +# This file permits to launch docker images of services required for this app +# +services: + + # launch it with ' docker compose up -d redis' + redis: + image: redis:latest + ports: + - 6378:6379 + + # launch it with ' docker compose up -d pubsub' + pubsub: + image: gcr.io/google.com/cloudsdktool/google-cloud-cli:latest + ports: + - 8085:8085 + command: gcloud beta emulators pubsub start + + # could not manage to make it work (port issue?) + # instead you can use the emulator on your workstation + # by launching "gcloud beta emulators datastore start" + datastore: + image: gcr.io/google.com/cloudsdktool/google-cloud-cli:latest + command: gcloud beta emulators datastore start --project flyxc + ports: + - 8081:8081 diff --git a/libs/optimizer/.babelrc b/libs/optimizer/.babelrc new file mode 100644 index 00000000..f2f38067 --- /dev/null +++ b/libs/optimizer/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@nx/js/babel"] +} diff --git a/libs/optimizer/.eslintrc.json b/libs/optimizer/.eslintrc.json new file mode 100644 index 00000000..adbe7ae2 --- /dev/null +++ b/libs/optimizer/.eslintrc.json @@ -0,0 +1,25 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": "error" + } + } + ] +} diff --git a/libs/optimizer/README.md b/libs/optimizer/README.md new file mode 100644 index 00000000..87ff2b73 --- /dev/null +++ b/libs/optimizer/README.md @@ -0,0 +1,30 @@ +# optimizer + +This library was generated with [Nx](https://nx.dev). + +## Description + +This library computes scores for flights using applicable rules of various XC leagues. + +## Usage + +The `src/lib/optimizer.ts#optimize` function computes score of a given track given by a `ScoringTrack` for a given league known by it's `LeagueCode`. +You can specify `OptimizationOptions` to limit either the number of the iterations performed during the optimization (`OptimizationOptions.maxLoop`) +or the maximum duration in milliseconds allowed for the optimization. + +The `optimize` function is a generator function. It returns an `Iterator`. You should call the `next()` +method of this iterator to get the current `IteratorResult`. The `value` property of the `IteratorResult` +gives the current `OptimizationResult` and the `done` property of the `IteratorResult` indicates if the optimization is terminated or not. + +If the `done` property is false, you should call again the `next()` method of the iterator so that you get another result that should be a better +optimization result. If you want to get the best optimisation, you should repeat the process until `done` is true. + +See an example in `optimizer.spec.ts#expectOptimizationIsAsExpected` + +## Building + +Run `nx build optimizer` to build the library. + +## Running unit tests + +Run `nx test optimizer` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/optimizer/jest.config.ts b/libs/optimizer/jest.config.ts new file mode 100644 index 00000000..b187e307 --- /dev/null +++ b/libs/optimizer/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'optimizer', + preset: '../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../coverage/libs/optimizer', +}; diff --git a/libs/optimizer/project.json b/libs/optimizer/project.json new file mode 100644 index 00000000..2f31cb68 --- /dev/null +++ b/libs/optimizer/project.json @@ -0,0 +1,20 @@ +{ + "name": "@flyxc/optimizer", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/optimizer/src", + "projectType": "library", + "targets": { + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"] + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/optimizer/jest.config.ts" + } + } + }, + "tags": [] +} diff --git a/libs/optimizer/src/index.ts b/libs/optimizer/src/index.ts new file mode 100644 index 00000000..c35af768 --- /dev/null +++ b/libs/optimizer/src/index.ts @@ -0,0 +1,10 @@ +export { getOptimizer } from './lib/optimizer'; +export type { + LatLonAltTime, + CircuitType, + ScoringTrack, + OptimizationResult, + OptimizationOptions, + OptimizationRequest, +} from './lib/optimizer'; +export type { ScoringRules } from './lib/scoringRules'; diff --git a/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts b/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts new file mode 100644 index 00000000..19bff255 --- /dev/null +++ b/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts @@ -0,0 +1,456 @@ +import { OptimizationRequest, OptimizationResult, CircuitType } from '../optimizer'; +import { computeDestinationPoint, getGreatCircleBearing, getPreciseDistance } from 'geolib'; +import { createSegments } from '../utils/createSegments'; +import { mergeTracks } from '../utils/mergeTracks'; +import { ScoringRules } from '../scoringRules'; + +/** + * Functions to generate test fixtures for the optimizer tests + */ + +/** + * Test fixture for the optimizer tests + * givenRequest: the OptimizationRequest to test the optimizer + * expectedResult: the expected OptimizationResult that should be returned by the optimizer + */ +export type OptimizerFixture = { + request: OptimizationRequest; + rules: ScoringRules; + expectedResult: Omit; +}; + +/** + * returns an empty track and its expected score + */ +export function createEmptyTrackFixture(): OptimizerFixture { + return { + request: { + track: { points: [], startTimeSec: 0 }, + }, + rules: 'FederationFrancaiseVolLibre', + expectedResult: { + score: 0, + lengthKm: 0, + multiplier: 0, + circuit: undefined, + optimal: true, + }, + }; +} + +export type LatLon = { + lat: number; + lon: number; +}; + +const START_TIME_SEC = Math.round(new Date().getTime() / 1000); +/** + * @param from LatLon of the starting point + * @param to LatLon of the ending point + * @param nbSegments number of segments to create between the two points + * @param givenRules the ScoringRules for computing the score + * @returns a fixture for a free distance track and it's expected score + */ +export function createFreeDistanceFixture( + from: LatLon, + to: LatLon, + nbSegments: number, + givenRules: ScoringRules, +): OptimizerFixture { + const multiplier = getFreeDistanceMultiplier(givenRules); + const distance = getPreciseDistance(from, to) / 1000; + return { + request: { + track: createSegments( + { ...from, alt: 0, timeSec: 0 }, + { ...to, alt: 0, timeSec: 60 }, + START_TIME_SEC, + nbSegments, + ), + }, + rules: givenRules, + expectedResult: { + score: distance * multiplier, + lengthKm: distance, + multiplier, + circuit: CircuitType.OpenDistance, + optimal: true, + }, + }; +} + +/** + * + * @param from LatLon of the starting point + * @param intermediate LatLon of the intermediate turn point + * @param to LatLon of the ending point + * @param nbSegments number of segments to create between each given points + * @param givenRules the ScoringRules for computing the score + * @returns a fixture for a free distance track with one intermediate turn point point and it's expected score + */ +export function createFreeDistance1PointFixture( + from: LatLon, + intermediate: LatLon, + to: LatLon, + nbSegments: number, + givenRules: ScoringRules, +): OptimizerFixture { + const distance = (getPreciseDistance(from, intermediate) + getPreciseDistance(intermediate, to)) / 1000; + const multiplier = getFreeDistanceMultiplier(givenRules); + return { + request: { + track: mergeTracks( + createSegments( + { ...from, alt: 0, timeSec: 0 }, + { ...intermediate, alt: 0, timeSec: 60 }, + START_TIME_SEC, + nbSegments, + ), + createSegments( + { ...intermediate, alt: 0, timeSec: 60 }, + { ...to, alt: 0, timeSec: 120 }, + START_TIME_SEC, + nbSegments, + ), + ), + }, + rules: givenRules, + expectedResult: { + score: distance * multiplier, + lengthKm: distance, + multiplier, + circuit: CircuitType.OpenDistance, + optimal: true, + }, + }; +} + +/** + * + * @param from LatLon of the starting point + * @param turnPoint1 LatLon of the first intermediate turn point + * @param turnPoint2 LatLon of the second intermediate turn point + * @param to LatLon of the ending point + * @param nbSegments number of segments to create between each given points + * @param givenRules the ScoringRules for computing the score + * @returns a fixture for a free distance track with two intermediate turn points and it's expected score + */ +export function createFreeDistance2PointsFixture( + from: LatLon, + turnPoint1: LatLon, + turnPoint2: LatLon, + to: LatLon, + nbSegments: number, + givenRules: ScoringRules, +): OptimizerFixture { + const distance = + (getPreciseDistance(from, turnPoint1) + + getPreciseDistance(turnPoint1, turnPoint2) + + getPreciseDistance(turnPoint2, to)) / + 1000; + const multiplier = getFreeDistanceMultiplier(givenRules); + return { + request: { + track: mergeTracks( + createSegments( + { ...from, alt: 0, timeSec: 0 }, + { ...turnPoint1, alt: 0, timeSec: 60 }, + START_TIME_SEC, + nbSegments, + ), + createSegments( + { ...turnPoint1, alt: 0, timeSec: 60 }, + { ...turnPoint2, alt: 0, timeSec: 120 }, + START_TIME_SEC, + nbSegments, + ), + createSegments( + { ...turnPoint2, alt: 0, timeSec: 120 }, + { ...to, alt: 0, timeSec: 180 }, + START_TIME_SEC, + nbSegments, + ), + ), + }, + rules: givenRules, + expectedResult: { + score: distance * multiplier, + lengthKm: distance, + multiplier, + circuit: CircuitType.OpenDistance, + optimal: true, + }, + }; +} + +/** + * + * @param from LatLon of the starting point + * @param turnPoint1 LatLon of the first intermediate turn point + * @param turnPoint2 LatLon of the second intermediate turn point + * @param turnPoint3 LatLon of the third intermediate turn point + * @param to LatLon of the ending point + * @param nbSegments number of segments to create between each given points + * @param givenRules the ScoringRules for computing the score + * @returns a fixture for a free distance track with three intermediate turn points and it's expected score + */ +export function createFreeDistance3PointsFixture( + from: LatLon, + turnPoint1: LatLon, + turnPoint2: LatLon, + turnPoint3: LatLon, + to: LatLon, + nbSegments: number, + givenRules: ScoringRules, +): OptimizerFixture { + const distance = + (getPreciseDistance(from, turnPoint1) + + getPreciseDistance(turnPoint1, turnPoint2) + + getPreciseDistance(turnPoint2, turnPoint3) + + getPreciseDistance(turnPoint3, to)) / + 1000; + const multiplier = getFreeDistanceMultiplier(givenRules); + return { + request: { + track: mergeTracks( + createSegments( + { ...from, alt: 0, timeSec: 0 }, + { ...turnPoint1, alt: 0, timeSec: 60 }, + START_TIME_SEC, + nbSegments, + ), + createSegments( + { ...turnPoint1, alt: 0, timeSec: 60 }, + { ...turnPoint2, alt: 0, timeSec: 120 }, + START_TIME_SEC, + nbSegments, + ), + createSegments( + { ...turnPoint2, alt: 0, timeSec: 120 }, + { ...turnPoint3, alt: 0, timeSec: 180 }, + START_TIME_SEC, + nbSegments, + ), + createSegments( + { ...turnPoint3, alt: 0, timeSec: 180 }, + { ...to, alt: 0, timeSec: 240 }, + START_TIME_SEC, + nbSegments, + ), + ), + }, + rules: givenRules, + expectedResult: { + score: distance * multiplier, + lengthKm: distance, + multiplier, + circuit: CircuitType.OpenDistance, + optimal: true, + }, + }; +} + +/** + * + * @param start LatLon of the starting point of the flat triangle (first point of the triangle) + * @param turnPoint1 LatLon of the second point of the triangle + * @param turnPoint2 LatLon of the third point of the triangle + * @param nbSegments number of segments to create between each given points + * @param givenRules the ScoringRules for computing the score + * @returns a fixture for a flat triangle track and it's expected score + */ +export function createClosedFlatTriangleFixture( + start: LatLon, + turnPoint1: LatLon, + turnPoint2: LatLon, + nbSegments: number, + givenRules: ScoringRules, +): OptimizerFixture { + if (isFAI(start, turnPoint1, turnPoint2)) { + throw new Error('invalid test data: not a flat triangle'); + } + const multiplier = getFlatTriangleMultiplier(givenRules); + return createTriangleFixture(start, turnPoint1, turnPoint2, nbSegments, givenRules, multiplier, CircuitType.FlatTriangle); +} + +/** + * + * @param start LatLon of the starting point of the flat triangle (first point of the triangle) + * @param turnPoint1 LatLon of the second point of the triangle + * @param nbSegments number of segments to create between each given points + * @param givenRules the ScoringRules for computing the score + * @returns a fixture for a FAI triangle track and it's expected score + * + * The third point of the triangle is computed so that the triangle is equilateral + */ +export function createClosedFaiTriangleFixture( + start: LatLon, + turnPoint1: LatLon, + nbSegments: number, + givenRules: ScoringRules, +): OptimizerFixture { + const distance1 = getPreciseDistance(start, turnPoint1); + const bearingStartToP1 = getGreatCircleBearing(start, turnPoint1); + // The third point 'p2' is at 'distance1' from 'p1' on a line which makes a 60° angle with the line 'start'->'p1' + const equilateralPoint = computeDestinationPoint(start, distance1, bearingStartToP1 + 60); + const p2 = { lat: equilateralPoint.latitude, lon: equilateralPoint.longitude }; + if (!isFAI(start, turnPoint1, p2)) { + throw new Error('invalid test data: not a FAI triangle'); + } + const multiplier = getFaiTriangleMultiplier(givenRules); + return createTriangleFixture(start, turnPoint1, p2, nbSegments, givenRules, multiplier, CircuitType.FaiTriangle); +} + +/** + * same as closedFaiTriangleFixture with a maximum allowed cycle duration of 1 ms for optimization + */ +export function createClosedFaiTriangleFixtureWithSmallCycle( + start: LatLon, + p1: LatLon, + nbIntervals: number, + givenRules: ScoringRules, +): OptimizerFixture { + const standardFixture = createClosedFaiTriangleFixture(start, p1, nbIntervals, givenRules); + return { + request: { + ...standardFixture.request, + options: { + maxCycleDurationMs: 1, + }, + }, + rules: givenRules, + expectedResult: standardFixture.expectedResult, + }; +} + +/** + * same as closedFaiTriangleFixture with a only ten iterations allowed for optimization + */ +export function createClosedFaiTriangleFixtureWithSmallLoop( + start: LatLon, + p1: LatLon, + nbIntervals: number, + givenRules: ScoringRules, +): OptimizerFixture { + const standardFixture = createClosedFaiTriangleFixture(start, p1, nbIntervals, givenRules); + return { + request: { + ...standardFixture.request, + options: { + maxNumCycles: 10, + }, + }, + rules: givenRules, + expectedResult: standardFixture.expectedResult, + }; +} + +function getFreeDistanceMultiplier(scoringRules: ScoringRules) { + switch (scoringRules) { + case 'CzechLocal': + case 'CzechEuropean': + case 'FederationFrancaiseVolLibre': + case 'Norway': + case 'UnitedKingdomClub': + case 'UnitedKingdomInternational': + case 'UnitedKingdomNational': + case 'XContest': + case 'XContestPPG': + case 'WorldXC': + return 1; + case 'CzechOutsideEurope': + return 0.8; + case 'Leonardo': + return 1.5; + } +} + +function getFlatTriangleMultiplier(scoringRules: ScoringRules) { + switch (scoringRules) { + case 'CzechEuropean': + case 'CzechOutsideEurope': + case 'FederationFrancaiseVolLibre': + case 'UnitedKingdomInternational': + return 1.2; + case 'Leonardo': + case 'WorldXC': + return 1.75; + case 'XContest': + return 1.4; + case 'Norway': + case 'UnitedKingdomClub': + case 'UnitedKingdomNational': + return 1.7; + case 'CzechLocal': + return 1.8; + case 'XContestPPG': + return 2; + } +} + +function getFaiTriangleMultiplier(scoringRules: ScoringRules) { + switch (scoringRules) { + case 'CzechEuropean': + case 'CzechOutsideEurope': + case 'FederationFrancaiseVolLibre': + return 1.4; + case 'Leonardo': + case 'UnitedKingdomClub': + case 'UnitedKingdomNational': + case 'WorldXC': + return 2; + case 'XContest': + return 1.6; + case 'CzechLocal': + return 2.2; + case 'Norway': + return 2.4; + case 'UnitedKingdomInternational': + return 1.5; + case 'XContestPPG': + return 4; + } +} + +function isFAI(p1: LatLon, p2: LatLon, p3: LatLon) { + const distance1 = getPreciseDistance(p1, p2); + const distance2 = getPreciseDistance(p2, p3); + const distance3 = getPreciseDistance(p3, p1); + const totalDistance = distance1 + distance2 + distance3; + const minDistance = Math.min(distance1, distance2, distance3); + const threshold = totalDistance * 0.28; + return minDistance > threshold; +} + +function createTriangleFixture( + start: LatLon, + p1: LatLon, + p2: { lon: number; lat: number }, + nbSegments: number, + givenRules: ScoringRules, + multiplier: number, + circuit: CircuitType, +): OptimizerFixture { + const distance1 = getPreciseDistance(start, p1); + const distance2 = getPreciseDistance(p1, p2); + const distance3 = getPreciseDistance(p2, start); + const lengthKm = (distance1 + distance2 + distance3) / 1000; + const expectedScore = lengthKm * multiplier; + return { + request: { + track: mergeTracks( + createSegments({ ...start, alt: 0, timeSec: 0 }, { ...p1, alt: 0, timeSec: 60 }, START_TIME_SEC, nbSegments), + createSegments({ ...p1, alt: 0, timeSec: 60 }, { ...p2, alt: 0, timeSec: 120 }, START_TIME_SEC, nbSegments), + createSegments({ ...p2, alt: 0, timeSec: 120 }, { ...start, alt: 0, timeSec: 180 }, START_TIME_SEC, nbSegments), + ), + }, + rules: givenRules, + expectedResult: { + score: expectedScore, + lengthKm, + multiplier, + circuit, + optimal: true, + }, + }; +} diff --git a/libs/optimizer/src/lib/optimizer.spec.ts b/libs/optimizer/src/lib/optimizer.spec.ts new file mode 100644 index 00000000..447c3888 --- /dev/null +++ b/libs/optimizer/src/lib/optimizer.spec.ts @@ -0,0 +1,153 @@ +import { OptimizationResult, getOptimizer } from './optimizer'; +import { + createClosedFaiTriangleFixture, + createClosedFaiTriangleFixtureWithSmallCycle, + createClosedFaiTriangleFixtureWithSmallLoop, + createClosedFlatTriangleFixture, + createEmptyTrackFixture, + createFreeDistance1PointFixture, + createFreeDistance2PointsFixture, + createFreeDistance3PointsFixture, + createFreeDistanceFixture, + OptimizerFixture, +} from './fixtures/optimizer.fixtures'; +import { scoringRulesNames } from './scoringRules'; + +describe('optimizer', () => { + describe('given an empty request', () => { + const fixture = createEmptyTrackFixture(); + it('should return a 0 score', () => { + expectOptimizationIsAsExpected(fixture); + }); + }); + scoringRulesNames.forEach((rules) => { + describe(`${rules} rules`, () => { + const oneSegmentPerBranch = 1; + const tenSegmentsPerBranch = 10; + [oneSegmentPerBranch, tenSegmentsPerBranch].forEach((nbSegmentsPerBranch) => { + describe(`given a free distance request (${nbSegmentsPerBranch} segments/branch)`, () => { + const fixture = createFreeDistanceFixture( + { lat: 45, lon: 5 }, + { lat: 45, lon: 6 }, + nbSegmentsPerBranch, + rules, + ); + it('should return the expected score', () => { + expectOptimizationIsAsExpected(fixture); + }); + }); + + describe(`given a free distance with 1 intermediate point request (${nbSegmentsPerBranch} segment/branch)`, () => { + const fixture = createFreeDistance1PointFixture( + { lat: 45, lon: 5 }, + { lat: 45, lon: 6 }, + { lat: 46, lon: 6 }, + nbSegmentsPerBranch, + rules, + ); + it('should return the expected score', () => { + expectOptimizationIsAsExpected(fixture); + }); + }); + + describe(`given a free distance with 2 intermediate points request (${nbSegmentsPerBranch} segment/branch)`, () => { + const fixture = createFreeDistance2PointsFixture( + { lat: 45, lon: 5 }, + { lat: 45, lon: 6 }, + { lat: 46, lon: 6 }, + { lat: 46, lon: 5 }, + nbSegmentsPerBranch, + rules, + ); + it('should return the expected score (' + nbSegmentsPerBranch + ' segment/branch)', () => { + expectOptimizationIsAsExpected(fixture); + }); + }); + + describe(`given a free distance with 3 intermediate points request (${nbSegmentsPerBranch} segment/branch)`, () => { + const fixture = createFreeDistance3PointsFixture( + { lat: 45, lon: 5 }, + { lat: 45, lon: 6 }, + { lat: 46, lon: 6 }, + { lat: 46, lon: 5 }, + { lat: 47, lon: 5 }, + nbSegmentsPerBranch, + rules, + ); + it('should return the expected score', () => { + expectOptimizationIsAsExpected(fixture); + }); + }); + + describe(`given a closed flat triangle request (${nbSegmentsPerBranch} segment/branch)`, () => { + const fixture = createClosedFlatTriangleFixture( + { lat: 45, lon: 5 }, + { lat: 45, lon: 6 }, + { lat: 45.2, lon: 6 }, + nbSegmentsPerBranch, + rules, + ); + it('should return the expected score', () => { + expectOptimizationIsAsExpected(fixture); + }); + }); + + describe(`given a closed FAI triangle request (${nbSegmentsPerBranch} segment/branch)`, () => { + const fixture = createClosedFaiTriangleFixture( + { lat: 45, lon: 5 }, + { lat: 45, lon: 6 }, + nbSegmentsPerBranch, + rules, + ); + it('should return the expected score', () => { + expectOptimizationIsAsExpected(fixture); + }); + }); + }); + }); + }); + + describe('given a closed FAI triangle request (10 segments/branch) with minimal cycle allowed', () => { + const fixture = createClosedFaiTriangleFixtureWithSmallCycle( + { lat: 45, lon: 5 }, + { lat: 45, lon: 6 }, + 9, + 'FederationFrancaiseVolLibre', + ); + it('should return the expected score', () => { + expectOptimizationIsAsExpected(fixture); + }); + }); + + describe('given a closed FAI triangle request (10 segments/branch) with minimal loop allowed', () => { + const fixture = createClosedFaiTriangleFixtureWithSmallLoop( + { lat: 45, lon: 5 }, + { lat: 45, lon: 6 }, + 9, + 'FederationFrancaiseVolLibre', + ); + it('should return the expected score', () => { + expectOptimizationIsAsExpected(fixture); + }); + }); + + // TODO: IsAsExpected does not really describe the behavior. Something with expect(optimize(...)).toHaveScore(...); + // should be better + function expectOptimizationIsAsExpected(fixture: OptimizerFixture) { + const optimization = getOptimizer(fixture.request, fixture.rules); + let currentResult: IteratorResult, + done = false; + while (!done) { + currentResult = optimization.next(); + done = currentResult.done; + } + expect(currentResult.value.score).toBeCloseTo(fixture.expectedResult.score, 1); + expect(currentResult.value.lengthKm).toBeCloseTo(fixture.expectedResult.lengthKm, 1); + expect(currentResult.value.multiplier).toEqual(fixture.expectedResult.multiplier); + expect(currentResult.value.circuit).toEqual(fixture.expectedResult.circuit); + currentResult.value.solutionIndices.forEach((index) => { + expect(index).toBeGreaterThanOrEqual(0); + expect(index).toBeLessThan(fixture.request.track.points.length); + }); + } +}); diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts new file mode 100644 index 00000000..e8f35a18 --- /dev/null +++ b/libs/optimizer/src/lib/optimizer.ts @@ -0,0 +1,335 @@ +import { Solution, solver } from 'igc-xc-score'; +import { BRecord, IGCFile } from 'igc-parser'; +import { createSegments } from './utils/createSegments'; +import { mergeTracks } from './utils/mergeTracks'; +import { ScoringRules, scoringRules } from './scoringRules'; +import { getDistance } from 'geolib'; + +// When the track has not enough points (<5), we build a new one by adding interpolated points between existing ones. +// see this issue https://github.com/mmomtchev/igc-xc-score/issues/231 +const MIN_POINTS = 5; +const NUM_SEGMENTS_BETWEEN_POINTS = 2; + +// For adding interpolated points, this constant adjusts the proximity of the points to the starting point of +// the segment. We want the added points to be very close to the starting points of the segment so that the solution +// points returned by the solver are as close as possible (or may be equal) to one of the original points of the track. +const DISTRIBUTION_FACTOR_FOR_ADDED_POINTS = 1e-5; + +// TODO: all console.xxx statements are commented. In the future, we should use a logging library + +export interface LatLonAltTime { + alt: number; + lat: number; + lon: number; + /** + * time in seconds elapsed since the beginning of the track (see ScoringTrack.startTimeSec) + */ + timeSec: number; +} + +export interface ScoringTrack { + /** + * the points that describe the track + */ + points: LatLonAltTime[]; + /** + * Timestamp in seconds + * the "timeSec" values in LatLonAltTime's are offsets according to this timestamp. + */ + startTimeSec: number; +} + +export interface OptimizationOptions { + /** + * maximum duration in milliseconds for an optimization round trip. + * If undefined, calculation duration is unbounded. + */ + maxCycleDurationMs?: number; + /** + * maximum number of iterations allowed for an optimization round trip. + * If undefined, number of allowed iterations is unbounded + */ + maxNumCycles?: number; +} + +/** + * optimize function argument + */ +export interface OptimizationRequest { + track: ScoringTrack; + options?: OptimizationOptions; +} + +export enum CircuitType { + OpenDistance = 'Open distance', + FlatTriangle = 'Flat triangle', + FaiTriangle = 'Fai triangle', + OutAndReturn = 'Out and return', +} + +export interface OptimizationResult { + /** + * the score for the track in the given league + */ + score: number; + /** + * the length of the optimized track in kms + */ + lengthKm: number; + /** + * multiplier for computing score. score = lengthKm * multiplier + */ + multiplier: number; + /** + * type of the optimized track + */ + circuit?: CircuitType; + /** + * if applicable, distance in m for closing the circuit + */ + closingRadius?: number; + /** + * indices of solutions points in ScoringTrack.points array + */ + solutionIndices: number[]; + /** + * the result is optimal (no need to get a next result of Iterator) + */ + optimal: boolean; +} + +const ZERO_SCORE: OptimizationResult = { + score: 0, + lengthKm: 0, + multiplier: 0, + solutionIndices: [], + optimal: true, +}; + +/** + * returns an iterative optimizer that computes iteratively the score for the flight. At each iteration, the score + * should be a better solutions. + * @param request the OptimizationRequest. if request.options is undefined, then there will be one iteration, and the result + * will be the best solution + * @param rules the ScoringRules to apply for computation + * @return an Iterator over the successive OptimizationResult + * @see README.md + */ +export function* getOptimizer( + request: OptimizationRequest, + rules: ScoringRules, +): Iterator { + if (request.track.points.length == 0) { + // console.warn('Empty track received in optimization request. Returns a 0 score'); + return ZERO_SCORE; + } + const originalTrack = request.track; + const solverTrack = buildValidTrackForSolver(originalTrack); + const flight = toIgcFile(solverTrack); + const solverScoringRules = scoringRules.get(rules); + const options = toSolverOptions(request.options); + const solutionIterator = solver(flight, solverScoringRules || {}, options); + while (true) { + const solution = solutionIterator.next(); + if (solution.done) { + // console.debug('solution', JSON.stringify(solution.value, undefined, 2)); + return toOptimizationResult(solution.value, originalTrack, solverTrack); + } + yield toOptimizationResult(solution.value, originalTrack, solverTrack); + } +} + +/** + * the solver requires at least 5 points, so if there is not enough points, + * we create points between existing ones + */ +function buildValidTrackForSolver(track: ScoringTrack) { + if (track.points.length >= MIN_POINTS) { + return track; + } + // console.debug(`not enough points (${track.points.length}) in track. Interpolate intermediate points`); + track = deepCopy(track); + while (track.points.length < MIN_POINTS) { + const segments: ScoringTrack[] = []; + for (let i = 1; i < track.points.length; i++) { + // split each segment of the track into two segments + segments.push( + createSegments( + track.points[i - 1], + track.points[i], + track.startTimeSec, + NUM_SEGMENTS_BETWEEN_POINTS, + DISTRIBUTION_FACTOR_FOR_ADDED_POINTS, + ), + ); + } + track = mergeTracks(...segments); + } + // console.debug(`new track has ${newTrack.points.length} points`); + return track; +} + +/** + * create an igc file from a track + * @param track the source track + */ +function toIgcFile(track: ScoringTrack): IGCFile { + const fixes = track.points.map((point): BRecord => { + const timeMilliseconds = point.timeSec * 1000; + return { + timestamp: timeMilliseconds, + time: new Date(timeMilliseconds).toISOString(), + latitude: point.lat, + longitude: point.lon, + valid: true, + pressureAltitude: null, + gpsAltitude: point.alt, + extensions: {}, + fixAccuracy: null, + enl: null, + }; + }); + // we ignore some properties of the igc-file, as they are not required for the computation + // @ts-ignore + return { + date: new Date(track.startTimeSec * 1000).toISOString(), + fixes: fixes, + }; +} + +type SolverOptions = { maxloop?: number; maxcycle?: number }; + +function toSolverOptions(options?: OptimizationOptions): SolverOptions { + return { + maxcycle: options?.maxCycleDurationMs, + maxloop: options?.maxNumCycles, + }; +} + +function toOptimizationResult(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack): OptimizationResult { + return { + score: solution.score ?? 0, + lengthKm: solution.scoreInfo?.distance ?? 0, + multiplier: solution.opt.scoring.multiplier, + circuit: toCircuitType(solution.opt.scoring.code), + closingRadius: getClosingRadius(solution), + solutionIndices: getIndices(solution, originalTrack, solverTrack), + optimal: solution.optimal || false, + }; +} + +function getClosingRadius(solution: Solution) { + // @ts-ignore : closingDistanceFixed is not exposed by library + const closingDistanceFixed: number | undefined = solution.opt.scoring?.closingDistanceFixed; + // @ts-ignore : closingDistanceRelative is not exposed by library + const closingDistanceRelativeRatio: number | undefined = solution.opt.scoring?.closingDistanceRelative; + const closingDistanceRelative = + solution.scoreInfo?.distance && closingDistanceRelativeRatio + ? closingDistanceRelativeRatio * solution.scoreInfo?.distance + : undefined; + const closingDistance = solution.scoreInfo?.cp?.d; + if (closingDistance == null) { + return undefined; + } + if (closingDistanceFixed != null && closingDistance < closingDistanceFixed) { + return closingDistanceFixed; + } else if (closingDistanceRelative != null && closingDistance < closingDistanceRelative) { + return closingDistanceRelative; + } + return undefined; +} + +const circuitTypeCodes = ['od' , 'tri' , 'fai' , 'oar'] +type CircuitTypeCode = (typeof circuitTypeCodes)[number]; + +function toCircuitType(code: CircuitTypeCode) { + switch (code) { + case 'od': + return CircuitType.OpenDistance; + case 'fai': + return CircuitType.FaiTriangle; + case 'oar': + return CircuitType.OutAndReturn; + case 'tri': + return CircuitType.FlatTriangle; + } + throw new Error(`no CircuitType found for ${code}`); +} + +// return indices of solution points. This permit to identify the solution points in the ScoringTrack.points array +// it contains (when applicable): +// - the starting point +// - the 'in' closing point +// - the turn points +// - the 'out' closing point +// - the finish point +function getIndices(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack) { + const result: number[] = []; + pushInResult(getEntryPointsStartIndex(solution, originalTrack, solverTrack)); + pushInResult(getClosingPointsInIndex(solution, originalTrack, solverTrack)); + solution.scoreInfo?.tp + ?.map((turnPoint) => turnPoint.r) + .forEach((index) => pushInResult(getPointIndex(index, originalTrack, solverTrack))); + pushInResult(getClosingPointsOutIndex(solution, originalTrack, solverTrack)); + pushInResult(getEntryPointsFinishIndex(solution, originalTrack, solverTrack)); + return result; + + function pushInResult(index: number) { + if (index >= 0) { + result.push(index); + } + } +} + +function getEntryPointsStartIndex(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { + // console.debug('getEntryPointsStartIndex', solution.scoreInfo?.ep?.start.r); + return getPointIndex(solution.scoreInfo?.ep?.start.r, originalTrack, solverTrack); +} + +function getClosingPointsInIndex(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { + // console.debug('getClosingPointsInIndex', solution.scoreInfo?.cp?.in.r); + return getPointIndex(solution.scoreInfo?.cp?.in.r, originalTrack, solverTrack); +} + +function getClosingPointsOutIndex(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { + // console.debug('getClosingPointsOutIndex', solution.scoreInfo?.cp?.out.r); + return getPointIndex(solution.scoreInfo?.cp?.out.r, originalTrack, solverTrack); +} + +function getEntryPointsFinishIndex(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { + // console.debug('getEntryPointsFinishIndex', solution.scoreInfo?.ep?.finish.r); + return getPointIndex(solution.scoreInfo?.ep?.finish.r, originalTrack, solverTrack); +} + +function getPointIndex(index: number | undefined, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { + if (index === undefined) { + return -1; + } + return solutionContainsValidIndices(originalTrack, solverTrack) + ? index + : getIndexInOriginalTrack(index, originalTrack, solverTrack); +} + +function solutionContainsValidIndices(originalTrack: ScoringTrack, solverTrack: ScoringTrack): boolean { + return originalTrack.points.length === solverTrack.points.length; +} + +function getIndexInOriginalTrack(index: number, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { + const solutionPoint = solverTrack.points[index]; + let indexInOriginalTrack = -1; + let closestDistance = Number.MAX_VALUE; + for (let i = 0; i < originalTrack.points.length; i++) { + const point = originalTrack.points[i]; + const distance = getDistance(point, solutionPoint); + if (distance < closestDistance) { + closestDistance = distance; + indexInOriginalTrack = i; + } + } + return indexInOriginalTrack; +} + +// Not the most performant solution but is used only for slow dimension problems +function deepCopy(source: T): T { + return JSON.parse(JSON.stringify(source)); +} diff --git a/libs/optimizer/src/lib/scoringRules.ts b/libs/optimizer/src/lib/scoringRules.ts new file mode 100644 index 00000000..3a01dcfb --- /dev/null +++ b/libs/optimizer/src/lib/scoringRules.ts @@ -0,0 +1,112 @@ +import { scoringRules as xcScoreRules } from 'igc-xc-score'; + +export const scoringRulesNames = [ + 'CzechLocal', + 'CzechEuropean', + 'CzechOutsideEurope', + 'FederationFrancaiseVolLibre', + 'Leonardo', + 'Norway', + 'UnitedKingdomClub', + 'UnitedKingdomInternational', + 'UnitedKingdomNational', + 'XContest', + 'XContestPPG', + 'WorldXC', +]; +export type ScoringRules = (typeof scoringRulesNames)[number]; + +const scoringBaseModel = xcScoreRules['XContest']; +const openDistanceBase = scoringBaseModel[0]; +const freeTriangleBase = scoringBaseModel[1]; +const faiTriangleBase = scoringBaseModel[2]; +const outAndReturnBase = xcScoreRules['FAI-OAR'][0]; + +const czechLocalRule = [ + { ...openDistanceBase, multiplier: 1 }, + { ...freeTriangleBase, multiplier: 1.8 }, + { ...faiTriangleBase, multiplier: 2.2 }, +]; + +const czechEuropeRule = [ + { ...openDistanceBase, multiplier: 1 }, + { ...freeTriangleBase, multiplier: 1.2 }, + { ...faiTriangleBase, multiplier: 1.4 }, +]; + +const czechOutEuropeRule = [ + { ...openDistanceBase, multiplier: 0.8 }, + { ...freeTriangleBase, multiplier: 1.2 }, + { ...faiTriangleBase, multiplier: 1.4 }, +]; + +const leonardoRule = [ + { ...openDistanceBase, multiplier: 1.5 }, + { ...freeTriangleBase, multiplier: 1.75, closingDistanceRelative: 0.2 }, + { ...faiTriangleBase, multiplier: 2, closingDistanceRelative: 0.2 }, +]; + +const norwayRule = [ + { ...openDistanceBase, multiplier: 1 }, + { ...freeTriangleBase, multiplier: 1.7, closingDistanceRelative: 0.05 }, + { ...freeTriangleBase, multiplier: 1.5, closingDistanceRelative: 0.2 }, + { ...faiTriangleBase, multiplier: 2.4, closingDistanceRelative: 0.05 }, + { ...faiTriangleBase, multiplier: 2.2, closingDistanceRelative: 0.2 }, +]; + +const ukXclClubRule = [ + { ...openDistanceBase, multiplier: 1, minDistance: 5 }, + { ...outAndReturnBase, multiplier: 1.2, minDistance: 5 }, + { ...outAndReturnBase, multiplier: 1.3, minDistance: 15 }, + { ...outAndReturnBase, multiplier: 1.7, minDistance: 35 }, + { ...freeTriangleBase, multiplier: 1.2, minDistance: 5 }, + { ...freeTriangleBase, multiplier: 1.3, minDistance: 15 }, + { ...freeTriangleBase, multiplier: 1.7, minDistance: 35 }, + { ...faiTriangleBase, multiplier: 1.5, minDistance: 5 }, + { ...faiTriangleBase, multiplier: 1.7, minDistance: 15 }, + { ...faiTriangleBase, multiplier: 2, minDistance: 35 }, +]; + +const ukXclInternationalRule = [ + { ...openDistanceBase, multiplier: 1, minDistance: 10 }, + { ...outAndReturnBase, multiplier: 1.2, minDistance: 35 }, + { ...freeTriangleBase, multiplier: 1.2, minDistance: 35 }, + { ...faiTriangleBase, multiplier: 1.5, minDistance: 25 }, +]; + +const ukXclNationalRule = [ + { ...openDistanceBase, multiplier: 1, minDistance: 10 }, + { ...outAndReturnBase, multiplier: 1.3, minDistance: 15 }, + { ...outAndReturnBase, multiplier: 1.7, minDistance: 35 }, + { ...freeTriangleBase, multiplier: 1.3, minDistance: 15 }, + { ...freeTriangleBase, multiplier: 1.7, minDistance: 35 }, + { ...faiTriangleBase, multiplier: 1.7, minDistance: 15 }, + { ...faiTriangleBase, multiplier: 2, minDistance: 25 }, +]; + +const xContestPpgRule = [ + { ...openDistanceBase, multiplier: 1 }, + { ...freeTriangleBase, multiplier: 2, closingDistanceFixed: 0.8 }, + { ...faiTriangleBase, multiplier: 4, closingDistanceFixed: 0.8 }, +]; + +const wxcRule = [ + { ...openDistanceBase, multiplier: 1 }, + { ...freeTriangleBase, multiplier: 1.75, closingDistanceRelative: 0.2 }, + { ...faiTriangleBase, multiplier: 2, closingDistanceFixed: 0.2 }, +]; + +export const scoringRules: Map = new Map([ + ['CzechEuropean', czechEuropeRule], + ['CzechLocal', czechLocalRule], + ['CzechOutsideEurope', czechOutEuropeRule], + ['FederationFrancaiseVolLibre', xcScoreRules['FFVL']], + ['Leonardo', leonardoRule], + ['Norway', norwayRule], + ['UnitedKingdomClub', ukXclClubRule], + ['UnitedKingdomInternational', ukXclInternationalRule], + ['UnitedKingdomNational', ukXclNationalRule], + ['XContest', xcScoreRules['XContest']], + ['XContestPPG', xContestPpgRule], + ['WorldXC', wxcRule], +]); diff --git a/libs/optimizer/src/lib/utils/createSegments.ts b/libs/optimizer/src/lib/utils/createSegments.ts new file mode 100644 index 00000000..0b69d0d6 --- /dev/null +++ b/libs/optimizer/src/lib/utils/createSegments.ts @@ -0,0 +1,46 @@ +import { LatLonAltTime, ScoringTrack } from '../optimizer'; + +/** + * Create segments between 2 points. + * Added points are computed by a linear interpolation + * @param from start point of the segment + * @param to end point + * @param minTimeSec time in seconds since 1970-01-01T00:00:00.000 when the track starts + * @param nbSegments number of segments created. If nbSegments <= 1 the result contains one segment ('from' -> 'to') + * @param distributionFactor if nbSegments > 1, this factor will narrow the distance between generated points and the start + * point of the segment. if close to zero, points will be close to the start point. + * if equals 1, points will be equally distributed along the segment. + * @return a ScoringTrack of nbSegments + */ +export function createSegments( + from: LatLonAltTime, + to: LatLonAltTime, + minTimeSec: number, + nbSegments: number, + distributionFactor = 1, +): ScoringTrack { + const result: ScoringTrack = { points: [], startTimeSec: minTimeSec }; + + result.points.push(from); + + if (nbSegments > 1) { + appendIntermediatePoints(); + } + result.points.push(to); + return result; + + function appendIntermediatePoints() { + const deltaLat = ((to.lat - from.lat) * distributionFactor) / nbSegments; + const deltaLon = ((to.lon - from.lon) * distributionFactor) / nbSegments; + const deltaAlt = ((to.alt - from.alt) * distributionFactor) / nbSegments; + const deltaTimeSec = ((to.timeSec - from.timeSec) * distributionFactor) / nbSegments; + for (let index = 1; index < nbSegments; index++) { + result.points.push({ + lat: from.lat + deltaLat * index, + lon: from.lon + deltaLon * index, + alt: Math.round(from.alt + deltaAlt * index), + timeSec: from.timeSec + deltaTimeSec * index, + }); + } + } +} diff --git a/libs/optimizer/src/lib/utils/mergeTracks.ts b/libs/optimizer/src/lib/utils/mergeTracks.ts new file mode 100644 index 00000000..93278c3e --- /dev/null +++ b/libs/optimizer/src/lib/utils/mergeTracks.ts @@ -0,0 +1,23 @@ +import { ScoringTrack } from '../optimizer'; + +/** + * merge multiple tracks into one track. + * it removes duplicated points between each end and start of consecutive tracks + * @param tracks the tracks to concatenate + * @return a track + */ +export function mergeTracks(...tracks: ScoringTrack[]): ScoringTrack { + const concatenated: ScoringTrack = { + points: [], + startTimeSec: 0, + }; + + for (const track of tracks) { + const skipFirstPoint = + concatenated.points.at(-1)?.lat === track.points[0].lat && + concatenated.points.at(-1)?.lon === track.points[0].lon; + const arrayToConcat = skipFirstPoint ? track.points.slice(1) : track.points; + concatenated.points = concatenated.points.concat(arrayToConcat); + } + return concatenated; +} diff --git a/libs/optimizer/tsconfig.json b/libs/optimizer/tsconfig.json new file mode 100644 index 00000000..62ebbd94 --- /dev/null +++ b/libs/optimizer/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/optimizer/tsconfig.lib.json b/libs/optimizer/tsconfig.lib.json new file mode 100644 index 00000000..33eca2c2 --- /dev/null +++ b/libs/optimizer/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/libs/optimizer/tsconfig.spec.json b/libs/optimizer/tsconfig.spec.json new file mode 100644 index 00000000..f6d8ffcc --- /dev/null +++ b/libs/optimizer/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/nx.json b/nx.json index d0b8901f..ef2b15ef 100644 --- a/nx.json +++ b/nx.json @@ -22,6 +22,11 @@ "@nx/eslint:lint": { "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], "cache": true + }, + "@nx/js:tsc": { + "cache": true, + "dependsOn": ["^build"], + "inputs": ["production", "^production"] } }, "namedInputs": { diff --git a/package-lock.json b/package-lock.json index dab14955..2a5fca75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,7 @@ "gpx-builder": "^5.3.0", "grant": "^5.4.22", "igc-parser": "^1.1.0", + "igc-xc-score": "^1.7.0", "ioredis": "^5.4.1", "lit": "^3.1.3", "lodepng": "^2.2.0", @@ -85,6 +86,7 @@ "@nx/webpack": "19.1.0", "@nx/workspace": "19.1.0", "@protobuf-ts/plugin": "^2.9.4", + "@swc/helpers": "~0.5.2", "@types/compression": "^1.7.5", "@types/csurf": "^1.11.5", "@types/d3-array": "^3.2.1", @@ -114,6 +116,7 @@ "jest": "^29.4.1", "jest-bench": "^29.4", "jest-environment-jsdom": "29.6.4", + "jest-environment-node": "^29.4.1", "jsdom": "~22.1.0", "mailersend": "^2.2.0", "nx": "19.1.0", @@ -8188,6 +8191,14 @@ "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", "dev": true }, + "node_modules/collections": { + "version": "5.1.13", + "resolved": "https://registry.npmjs.org/collections/-/collections-5.1.13.tgz", + "integrity": "sha512-SCb6Qd+d3Z02corWQ7/mqXiXeeTdHvkP6TeFSYfGYdCFp1WrjSNZ3j6y8Y3T/7osGEe0iOcU2g1d346l99m4Lg==", + "dependencies": { + "weak-map": "~1.0.x" + } + }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -10750,6 +10761,22 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/flatbush": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/flatbush/-/flatbush-4.4.0.tgz", + "integrity": "sha512-cf6G+sfy/+/FLH7Ls1URQ5GCRlXgwgqUZiEsMNrMZqb3Us3EkKmzUlKbnyoBy/4wI4oLJ+8cyCQoKJIVm92Fmg==", + "dependencies": { + "flatqueue": "^2.0.3" + } + }, + "node_modules/flatqueue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/flatqueue/-/flatqueue-2.0.3.tgz", + "integrity": "sha512-RZCWZNkmxzUOh8jqEcEGZCycb3B8KAfpPwg3H//cURasunYxsg1eIvE+QDSjX+ZPHTIVfINfK1aLTrVKKO0i4g==", + "engines": { + "node": ">= 12.17.0" + } + }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", @@ -12088,6 +12115,20 @@ "node": ">=12" } }, + "node_modules/igc-xc-score": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/igc-xc-score/-/igc-xc-score-1.7.0.tgz", + "integrity": "sha512-49UQM9mbXjTo2mmeRYIq0vszShw8bg8TKhTU2XGwBCmSk0ojJFACajeZKSB0dT8u3F6p+7ap1oRv17g22Xh3PA==", + "dependencies": { + "collections": "^5.1.13", + "flatbush": "^4.0.0", + "igc-parser": "^1.1.0", + "rbush": "^3.0.1" + }, + "bin": { + "igc-xc-score": "dist/igc-xc-score.cjs" + } + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -16717,6 +16758,11 @@ } ] }, + "node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + }, "node_modules/random-bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", @@ -16764,6 +16810,14 @@ "node": ">= 0.8" } }, + "node_modules/rbush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", + "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", + "dependencies": { + "quickselect": "^2.0.0" + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -19974,6 +20028,11 @@ "defaults": "^1.0.3" } }, + "node_modules/weak-map": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.8.tgz", + "integrity": "sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw==" + }, "node_modules/web-streams-polyfill": { "version": "4.0.0-beta.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", diff --git a/package.json b/package.json index b02f5e33..75405a6b 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@nx/webpack": "19.1.0", "@nx/workspace": "19.1.0", "@protobuf-ts/plugin": "^2.9.4", + "@swc/helpers": "~0.5.2", "@types/compression": "^1.7.5", "@types/csurf": "^1.11.5", "@types/d3-array": "^3.2.1", @@ -60,6 +61,7 @@ "jest": "^29.4.1", "jest-bench": "^29.4", "jest-environment-jsdom": "29.6.4", + "jest-environment-node": "^29.4.1", "jsdom": "~22.1.0", "mailersend": "^2.2.0", "nx": "19.1.0", @@ -114,6 +116,7 @@ "gpx-builder": "^5.3.0", "grant": "^5.4.22", "igc-parser": "^1.1.0", + "igc-xc-score": "^1.7.0", "ioredis": "^5.4.1", "lit": "^3.1.3", "lodepng": "^2.2.0", diff --git a/tsconfig.base.json b/tsconfig.base.json index f5986db2..123b7cfa 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -18,8 +18,9 @@ "paths": { "@flyxc/common": ["libs/common/src/index.ts"], "@flyxc/common-node": ["libs/common-node/src/index.ts"], + "@flyxc/optimizer": ["libs/optimizer/src/index.ts"], "@vaadin/dom": ["libs/vaadin-dom/src/index.ts"], - "@vaadin/nodom": ["libs/vaadin-nodom/src/index.ts"] + "@vaadin/nodom": ["libs/vaadin-nodom/src/index.ts"], } }, "exclude": ["node_modules", "tmp"] From 0d9693a9e672b99ced562856b0180ae8ad06f864 Mon Sep 17 00:00:00 2001 From: Christophe TARET Date: Thu, 16 May 2024 09:25:14 +0200 Subject: [PATCH 02/20] feat: add an optimizer library, use it in flyxc front XC planning. This library computes scores for flights using applicable rules of various XC leagues. It permit computations with small chunks of time or cycles. Optimizer can send successive results that are not optimal. This can be useful to interrupt optimization properly if it is too long. --- .../fxc-front/src/app/components/2d/path-element.ts | 4 ++-- apps/fxc-front/src/app/logic/score/scorer.ts | 13 +------------ libs/optimizer/src/index.ts | 3 +-- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/apps/fxc-front/src/app/components/2d/path-element.ts b/apps/fxc-front/src/app/components/2d/path-element.ts index 7a7cd1f6..554ab269 100644 --- a/apps/fxc-front/src/app/components/2d/path-element.ts +++ b/apps/fxc-front/src/app/components/2d/path-element.ts @@ -13,11 +13,11 @@ import { FaiSectors } from '../../gm/fai-sectors'; import { addAltitude } from '../../logic/elevation'; import { getCurrentUrl, pushCurrentState } from '../../logic/history'; import { drawRoute } from '../../logic/messages'; -import { CircuitType, Score } from '../../logic/score/scorer'; +import { Score } from '../../logic/score/scorer'; import { setDistance, setEnabled, setRoute, setScore } from '../../redux/planner-slice'; import { RootState, store } from '../../redux/store'; import { PlannerElement } from './planner-element'; -import { getOptimizer, ScoringTrack } from '@flyxc/optimizer'; +import { CircuitType, getOptimizer, ScoringTrack } from '@flyxc/optimizer'; import { getScoringRules } from '../../logic/score/league/leagues'; // Route color by circuit type. diff --git a/apps/fxc-front/src/app/logic/score/scorer.ts b/apps/fxc-front/src/app/logic/score/scorer.ts index 488b7fcc..ff74b5dd 100644 --- a/apps/fxc-front/src/app/logic/score/scorer.ts +++ b/apps/fxc-front/src/app/logic/score/scorer.ts @@ -1,15 +1,4 @@ -import { CircuitType as OptimizerCircuitType } from '@flyxc/optimizer'; - -export enum CircuitType { - OpenDistance = 'Open distance', - FlatTriangle = 'Flat triangle', - FaiTriangle = 'Fai triangle', - OutAndReturn = 'Out and return', -} - -export function getCircuitType(circuit?: OptimizerCircuitType) { - return circuit as unknown as CircuitType; -} +import { CircuitType } from '@flyxc/optimizer'; export class Score { distanceM: number; diff --git a/libs/optimizer/src/index.ts b/libs/optimizer/src/index.ts index c35af768..d95db7d8 100644 --- a/libs/optimizer/src/index.ts +++ b/libs/optimizer/src/index.ts @@ -1,7 +1,6 @@ -export { getOptimizer } from './lib/optimizer'; +export { getOptimizer, CircuitType } from './lib/optimizer'; export type { LatLonAltTime, - CircuitType, ScoringTrack, OptimizationResult, OptimizationOptions, From eda847fdc37b6314d3b8fa820694b5700aa3445c Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Fri, 31 May 2024 00:48:58 +0200 Subject: [PATCH 03/20] tweaks part 1 --- .../src/app/components/2d/path-element.ts | 5 +- libs/optimizer/README.md | 16 +- libs/optimizer/src/index.ts | 8 +- .../src/lib/fixtures/optimizer.fixtures.ts | 79 +++++---- libs/optimizer/src/lib/optimizer.ts | 161 ++++++++++-------- .../optimizer/src/lib/utils/createSegments.ts | 4 +- 6 files changed, 151 insertions(+), 122 deletions(-) diff --git a/apps/fxc-front/src/app/components/2d/path-element.ts b/apps/fxc-front/src/app/components/2d/path-element.ts index 554ab269..f2e88dab 100644 --- a/apps/fxc-front/src/app/components/2d/path-element.ts +++ b/apps/fxc-front/src/app/components/2d/path-element.ts @@ -252,15 +252,16 @@ export class PathElement extends connect(store)(LitElement) { private computeScore(points: LatLon[]): Score { const track: ScoringTrack = { - points: points.map((point, i) => ({ ...point, alt: 0, timeSec: i * 60 })), + points: points.map((point, i) => ({ ...point, alt: 0, offsetFromStartSec: i * 60 })), startTimeSec: Math.round(new Date().getTime() / 1000), }; + // TODO: limit the processing time ? const result = getOptimizer({ track }, getScoringRules(this.league)).next().value; return new Score({ circuit: result.circuit, distanceM: result.lengthKm * 1000, multiplier: result.multiplier, - closingRadiusM: result.closingRadius ? result.closingRadius * 1000 : null, + closingRadiusM: result.closingRadiusM ? result.closingRadiusM * 1000 : null, indexes: result.solutionIndices, points: result.score, }); diff --git a/libs/optimizer/README.md b/libs/optimizer/README.md index 87ff2b73..7b182cde 100644 --- a/libs/optimizer/README.md +++ b/libs/optimizer/README.md @@ -9,15 +9,17 @@ This library computes scores for flights using applicable rules of various XC le ## Usage The `src/lib/optimizer.ts#optimize` function computes score of a given track given by a `ScoringTrack` for a given league known by it's `LeagueCode`. -You can specify `OptimizationOptions` to limit either the number of the iterations performed during the optimization (`OptimizationOptions.maxLoop`) -or the maximum duration in milliseconds allowed for the optimization. -The `optimize` function is a generator function. It returns an `Iterator`. You should call the `next()` -method of this iterator to get the current `IteratorResult`. The `value` property of the `IteratorResult` -gives the current `OptimizationResult` and the `done` property of the `IteratorResult` indicates if the optimization is terminated or not. +The `optimize` function is a generator function. -If the `done` property is false, you should call again the `next()` method of the iterator so that you get another result that should be a better -optimization result. If you want to get the best optimisation, you should repeat the process until `done` is true. +It takes an `OptimizationRequest` describing containing the track an some options. + +It returns an `Iterator`. + +You should call the `next()` method of this iterator to get the current `IteratorResult`. +The `value` property of the `IteratorResult` gives the current `OptimizationResult` and the `done` property indicates whether the optimization is terminated. + +If the `done` property is false, you should call the `next()` method again to get a more optimal result. To get the best optimization, you should repeat the process until `done` is true. See an example in `optimizer.spec.ts#expectOptimizationIsAsExpected` diff --git a/libs/optimizer/src/index.ts b/libs/optimizer/src/index.ts index d95db7d8..6e941aa0 100644 --- a/libs/optimizer/src/index.ts +++ b/libs/optimizer/src/index.ts @@ -1,9 +1,3 @@ export { getOptimizer, CircuitType } from './lib/optimizer'; -export type { - LatLonAltTime, - ScoringTrack, - OptimizationResult, - OptimizationOptions, - OptimizationRequest, -} from './lib/optimizer'; +export type { LatLonAltTime, ScoringTrack, OptimizationResult, OptimizationRequest } from './lib/optimizer'; export type { ScoringRules } from './lib/scoringRules'; diff --git a/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts b/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts index 19bff255..99edf55c 100644 --- a/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts +++ b/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts @@ -62,8 +62,8 @@ export function createFreeDistanceFixture( return { request: { track: createSegments( - { ...from, alt: 0, timeSec: 0 }, - { ...to, alt: 0, timeSec: 60 }, + { ...from, alt: 0, offsetFromStartSec: 0 }, + { ...to, alt: 0, offsetFromStartSec: 60 }, START_TIME_SEC, nbSegments, ), @@ -101,14 +101,14 @@ export function createFreeDistance1PointFixture( request: { track: mergeTracks( createSegments( - { ...from, alt: 0, timeSec: 0 }, - { ...intermediate, alt: 0, timeSec: 60 }, + { ...from, alt: 0, offsetFromStartSec: 0 }, + { ...intermediate, alt: 0, offsetFromStartSec: 60 }, START_TIME_SEC, nbSegments, ), createSegments( - { ...intermediate, alt: 0, timeSec: 60 }, - { ...to, alt: 0, timeSec: 120 }, + { ...intermediate, alt: 0, offsetFromStartSec: 60 }, + { ...to, alt: 0, offsetFromStartSec: 120 }, START_TIME_SEC, nbSegments, ), @@ -153,20 +153,20 @@ export function createFreeDistance2PointsFixture( request: { track: mergeTracks( createSegments( - { ...from, alt: 0, timeSec: 0 }, - { ...turnPoint1, alt: 0, timeSec: 60 }, + { ...from, alt: 0, offsetFromStartSec: 0 }, + { ...turnPoint1, alt: 0, offsetFromStartSec: 60 }, START_TIME_SEC, nbSegments, ), createSegments( - { ...turnPoint1, alt: 0, timeSec: 60 }, - { ...turnPoint2, alt: 0, timeSec: 120 }, + { ...turnPoint1, alt: 0, offsetFromStartSec: 60 }, + { ...turnPoint2, alt: 0, offsetFromStartSec: 120 }, START_TIME_SEC, nbSegments, ), createSegments( - { ...turnPoint2, alt: 0, timeSec: 120 }, - { ...to, alt: 0, timeSec: 180 }, + { ...turnPoint2, alt: 0, offsetFromStartSec: 120 }, + { ...to, alt: 0, offsetFromStartSec: 180 }, START_TIME_SEC, nbSegments, ), @@ -214,26 +214,26 @@ export function createFreeDistance3PointsFixture( request: { track: mergeTracks( createSegments( - { ...from, alt: 0, timeSec: 0 }, - { ...turnPoint1, alt: 0, timeSec: 60 }, + { ...from, alt: 0, offsetFromStartSec: 0 }, + { ...turnPoint1, alt: 0, offsetFromStartSec: 60 }, START_TIME_SEC, nbSegments, ), createSegments( - { ...turnPoint1, alt: 0, timeSec: 60 }, - { ...turnPoint2, alt: 0, timeSec: 120 }, + { ...turnPoint1, alt: 0, offsetFromStartSec: 60 }, + { ...turnPoint2, alt: 0, offsetFromStartSec: 120 }, START_TIME_SEC, nbSegments, ), createSegments( - { ...turnPoint2, alt: 0, timeSec: 120 }, - { ...turnPoint3, alt: 0, timeSec: 180 }, + { ...turnPoint2, alt: 0, offsetFromStartSec: 120 }, + { ...turnPoint3, alt: 0, offsetFromStartSec: 180 }, START_TIME_SEC, nbSegments, ), createSegments( - { ...turnPoint3, alt: 0, timeSec: 180 }, - { ...to, alt: 0, timeSec: 240 }, + { ...turnPoint3, alt: 0, offsetFromStartSec: 180 }, + { ...to, alt: 0, offsetFromStartSec: 240 }, START_TIME_SEC, nbSegments, ), @@ -270,7 +270,15 @@ export function createClosedFlatTriangleFixture( throw new Error('invalid test data: not a flat triangle'); } const multiplier = getFlatTriangleMultiplier(givenRules); - return createTriangleFixture(start, turnPoint1, turnPoint2, nbSegments, givenRules, multiplier, CircuitType.FlatTriangle); + return createTriangleFixture( + start, + turnPoint1, + turnPoint2, + nbSegments, + givenRules, + multiplier, + CircuitType.FlatTriangle, + ); } /** @@ -314,9 +322,7 @@ export function createClosedFaiTriangleFixtureWithSmallCycle( return { request: { ...standardFixture.request, - options: { - maxCycleDurationMs: 1, - }, + maxCycleDurationMs: 1, }, rules: givenRules, expectedResult: standardFixture.expectedResult, @@ -336,9 +342,7 @@ export function createClosedFaiTriangleFixtureWithSmallLoop( return { request: { ...standardFixture.request, - options: { - maxNumCycles: 10, - }, + maxNumCycles: 10, }, rules: givenRules, expectedResult: standardFixture.expectedResult, @@ -439,9 +443,24 @@ function createTriangleFixture( return { request: { track: mergeTracks( - createSegments({ ...start, alt: 0, timeSec: 0 }, { ...p1, alt: 0, timeSec: 60 }, START_TIME_SEC, nbSegments), - createSegments({ ...p1, alt: 0, timeSec: 60 }, { ...p2, alt: 0, timeSec: 120 }, START_TIME_SEC, nbSegments), - createSegments({ ...p2, alt: 0, timeSec: 120 }, { ...start, alt: 0, timeSec: 180 }, START_TIME_SEC, nbSegments), + createSegments( + { ...start, alt: 0, offsetFromStartSec: 0 }, + { ...p1, alt: 0, offsetFromStartSec: 60 }, + START_TIME_SEC, + nbSegments, + ), + createSegments( + { ...p1, alt: 0, offsetFromStartSec: 60 }, + { ...p2, alt: 0, offsetFromStartSec: 120 }, + START_TIME_SEC, + nbSegments, + ), + createSegments( + { ...p2, alt: 0, offsetFromStartSec: 120 }, + { ...start, alt: 0, offsetFromStartSec: 180 }, + START_TIME_SEC, + nbSegments, + ), ), }, rules: givenRules, diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index e8f35a18..56725acd 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -6,7 +6,7 @@ import { ScoringRules, scoringRules } from './scoringRules'; import { getDistance } from 'geolib'; // When the track has not enough points (<5), we build a new one by adding interpolated points between existing ones. -// see this issue https://github.com/mmomtchev/igc-xc-score/issues/231 +// See this issue https://github.com/mmomtchev/igc-xc-score/issues/231 const MIN_POINTS = 5; const NUM_SEGMENTS_BETWEEN_POINTS = 2; @@ -22,44 +22,34 @@ export interface LatLonAltTime { lat: number; lon: number; /** - * time in seconds elapsed since the beginning of the track (see ScoringTrack.startTimeSec) + * TODO: make this an absolute time, remove the start time + * Time relative to the start of the track. */ - timeSec: number; + offsetFromStartSec: number; } export interface ScoringTrack { - /** - * the points that describe the track - */ points: LatLonAltTime[]; /** - * Timestamp in seconds - * the "timeSec" values in LatLonAltTime's are offsets according to this timestamp. + * Timestamp of the start of the track. */ startTimeSec: number; } -export interface OptimizationOptions { +export interface OptimizationRequest { + track: ScoringTrack; /** - * maximum duration in milliseconds for an optimization round trip. + * Maximum duration for an optimization round trip. * If undefined, calculation duration is unbounded. */ maxCycleDurationMs?: number; /** - * maximum number of iterations allowed for an optimization round trip. + * Maximum number of iterations allowed for an optimization round trip. * If undefined, number of allowed iterations is unbounded */ maxNumCycles?: number; } -/** - * optimize function argument - */ -export interface OptimizationRequest { - track: ScoringTrack; - options?: OptimizationOptions; -} - export enum CircuitType { OpenDistance = 'Open distance', FlatTriangle = 'Flat triangle', @@ -69,50 +59,46 @@ export enum CircuitType { export interface OptimizationResult { /** - * the score for the track in the given league + * The score for the track in the given league */ score: number; /** - * the length of the optimized track in kms + * The length of the optimized track in kms */ lengthKm: number; /** - * multiplier for computing score. score = lengthKm * multiplier + * TODO: we probably do not need all 3 of score, lengthKm, and multiplier. + * Multiplier for computing score. score = lengthKm * multiplier */ multiplier: number; /** - * type of the optimized track + * Type of the optimized track */ circuit?: CircuitType; /** - * if applicable, distance in m for closing the circuit + * If applicable, Distance in m for closing the circuit */ - closingRadius?: number; + closingRadiusM?: number; /** - * indices of solutions points in ScoringTrack.points array + * Indices of solutions points in the request */ solutionIndices: number[]; /** - * the result is optimal (no need to get a next result of Iterator) + * Whether the result is optimal. + * If not the optimizer can be cycled again to get a more accurate solution. */ optimal: boolean; } -const ZERO_SCORE: OptimizationResult = { - score: 0, - lengthKm: 0, - multiplier: 0, - solutionIndices: [], - optimal: true, -}; - /** - * returns an iterative optimizer that computes iteratively the score for the flight. At each iteration, the score - * should be a better solutions. + * Returns an iterative optimizer computing the score for the flight. + * + * At each iteration, the score should be a better solutions. + * * @param request the OptimizationRequest. if request.options is undefined, then there will be one iteration, and the result * will be the best solution * @param rules the ScoringRules to apply for computation - * @return an Iterator over the successive OptimizationResult + * @return an Iterator of OptimizationResult * @see README.md */ export function* getOptimizer( @@ -121,7 +107,13 @@ export function* getOptimizer( ): Iterator { if (request.track.points.length == 0) { // console.warn('Empty track received in optimization request. Returns a 0 score'); - return ZERO_SCORE; + return { + score: 0, + lengthKm: 0, + multiplier: 0, + solutionIndices: [], + optimal: true, + }; } const originalTrack = request.track; const solverTrack = buildValidTrackForSolver(originalTrack); @@ -175,7 +167,7 @@ function buildValidTrackForSolver(track: ScoringTrack) { */ function toIgcFile(track: ScoringTrack): IGCFile { const fixes = track.points.map((point): BRecord => { - const timeMilliseconds = point.timeSec * 1000; + const timeMilliseconds = point.offsetFromStartSec * 1000; return { timestamp: timeMilliseconds, time: new Date(timeMilliseconds).toISOString(), @@ -199,70 +191,91 @@ function toIgcFile(track: ScoringTrack): IGCFile { type SolverOptions = { maxloop?: number; maxcycle?: number }; -function toSolverOptions(options?: OptimizationOptions): SolverOptions { +function toSolverOptions(request: OptimizationRequest): SolverOptions { return { - maxcycle: options?.maxCycleDurationMs, - maxloop: options?.maxNumCycles, + maxcycle: request.maxCycleDurationMs, + maxloop: request.maxNumCycles, }; } -function toOptimizationResult(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack): OptimizationResult { +function toOptimizationResult( + solution: Solution, + originalTrack: ScoringTrack, + solverTrack: ScoringTrack, +): OptimizationResult { return { score: solution.score ?? 0, lengthKm: solution.scoreInfo?.distance ?? 0, multiplier: solution.opt.scoring.multiplier, circuit: toCircuitType(solution.opt.scoring.code), - closingRadius: getClosingRadius(solution), + closingRadiusM: getClosingRadiusM(solution), solutionIndices: getIndices(solution, originalTrack, solverTrack), optimal: solution.optimal || false, }; } -function getClosingRadius(solution: Solution) { - // @ts-ignore : closingDistanceFixed is not exposed by library - const closingDistanceFixed: number | undefined = solution.opt.scoring?.closingDistanceFixed; - // @ts-ignore : closingDistanceRelative is not exposed by library - const closingDistanceRelativeRatio: number | undefined = solution.opt.scoring?.closingDistanceRelative; - const closingDistanceRelative = - solution.scoreInfo?.distance && closingDistanceRelativeRatio - ? closingDistanceRelativeRatio * solution.scoreInfo?.distance - : undefined; +// TODO: submit a PR to igc-xc-score +interface Scoring { + closingDistanceFixed?: number; + closingDistanceRelative?: number; +} + +function getClosingRadiusM(solution: Solution): number | undefined { const closingDistance = solution.scoreInfo?.cp?.d; + if (closingDistance == null) { return undefined; } + + const closingDistanceFixed = solution.opt.scoring?.closingDistanceFixed; + if (closingDistanceFixed != null && closingDistance < closingDistanceFixed) { return closingDistanceFixed; - } else if (closingDistanceRelative != null && closingDistance < closingDistanceRelative) { + } + + const closingDistanceRelativeRatio = solution.opt.scoring?.closingDistanceRelative; + const closingDistanceRelative = + solution.scoreInfo?.distance != null && closingDistanceRelativeRatio != null + ? closingDistanceRelativeRatio * solution.scoreInfo.distance + : undefined; + + if (closingDistanceRelative != null && closingDistance < closingDistanceRelative) { return closingDistanceRelative; } + return undefined; } -const circuitTypeCodes = ['od' , 'tri' , 'fai' , 'oar'] +const circuitTypeCodes = ['od', 'tri', 'fai', 'oar']; type CircuitTypeCode = (typeof circuitTypeCodes)[number]; -function toCircuitType(code: CircuitTypeCode) { - switch (code) { - case 'od': - return CircuitType.OpenDistance; - case 'fai': - return CircuitType.FaiTriangle; - case 'oar': - return CircuitType.OutAndReturn; - case 'tri': - return CircuitType.FlatTriangle; +const circuitMapping = { + od: CircuitType.OpenDistance, + tri: CircuitType.FlatTriangle, + fai: CircuitType.FaiTriangle, + oar: CircuitType.OutAndReturn, +}; + +function toCircuitType(code: string): CircuitType { + const type = circuitMapping[code]; + if (type == null) { + throw new Error(`Unknown type "${code}"`); } - throw new Error(`no CircuitType found for ${code}`); + return type; } -// return indices of solution points. This permit to identify the solution points in the ScoringTrack.points array -// it contains (when applicable): -// - the starting point -// - the 'in' closing point -// - the turn points -// - the 'out' closing point -// - the finish point +/** + * Return the indices of the solution points. + * + * This permit to identify the solution points in the ScoringTrack.points array + * + * It contains (when applicable): + * - the starting point + * - the 'in' closing point + * - the turn points + * - the 'out' closing point + * - the end point + * */ function getIndices(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack) { const result: number[] = []; pushInResult(getEntryPointsStartIndex(solution, originalTrack, solverTrack)); diff --git a/libs/optimizer/src/lib/utils/createSegments.ts b/libs/optimizer/src/lib/utils/createSegments.ts index 0b69d0d6..66296a6e 100644 --- a/libs/optimizer/src/lib/utils/createSegments.ts +++ b/libs/optimizer/src/lib/utils/createSegments.ts @@ -33,13 +33,13 @@ export function createSegments( const deltaLat = ((to.lat - from.lat) * distributionFactor) / nbSegments; const deltaLon = ((to.lon - from.lon) * distributionFactor) / nbSegments; const deltaAlt = ((to.alt - from.alt) * distributionFactor) / nbSegments; - const deltaTimeSec = ((to.timeSec - from.timeSec) * distributionFactor) / nbSegments; + const deltaTimeSec = ((to.offsetFromStartSec - from.offsetFromStartSec) * distributionFactor) / nbSegments; for (let index = 1; index < nbSegments; index++) { result.points.push({ lat: from.lat + deltaLat * index, lon: from.lon + deltaLon * index, alt: Math.round(from.alt + deltaAlt * index), - timeSec: from.timeSec + deltaTimeSec * index, + offsetFromStartSec: from.offsetFromStartSec + deltaTimeSec * index, }); } } From 790d1cdd064d7b98b2f67b24d4ff2aaefa0f40c1 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Fri, 31 May 2024 13:02:18 +0200 Subject: [PATCH 04/20] tweaks part2 --- CONTRIBUTING.md | 6 +- .../src/app/components/2d/path-element.ts | 8 +- .../src/app/components/ui/pref-modal.ts | 6 +- .../src/app/logic/score/league/leagues.ts | 7 +- libs/optimizer/README.md | 10 +- libs/optimizer/project.json | 2 +- libs/optimizer/src/index.ts | 2 +- .../src/lib/fixtures/optimizer.fixtures.ts | 28 +-- libs/optimizer/src/lib/optimizer.ts | 198 +++++------------- libs/optimizer/src/lib/scoringRules.ts | 19 +- 10 files changed, 100 insertions(+), 186 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4c476100..65254868 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,6 +44,8 @@ For the moment, it does not work with docker compose. But if you install the clo - define the required environment variables:`eval $(gcloud beta emulators datastore --data-dir=MY_DATA_DIR env-init)` - you can then run the application locally in this shell with `npm run dev` -## Before you submit your PR: +## Helpful commands -run this command to format/lint/test: `npx nx check` +`npx nx check` runs the build, lint, and test targets for all the projects. Nice to use before uploading a PR. + +`nx affected:test --all --parallel --maxParallel 10 --watch` will run the tests affected by your code changes. diff --git a/apps/fxc-front/src/app/components/2d/path-element.ts b/apps/fxc-front/src/app/components/2d/path-element.ts index f2e88dab..ad542f65 100644 --- a/apps/fxc-front/src/app/components/2d/path-element.ts +++ b/apps/fxc-front/src/app/components/2d/path-element.ts @@ -194,8 +194,7 @@ export class PathElement extends connect(store)(LitElement) { if (!this.line || this.line.getPath().getLength() < 2 || this.doNotSyncState) { return; } - const line = this.line; - store.dispatch(setDistance(google.maps.geometry.spherical.computeLength(line.getPath()))); + store.dispatch(setDistance(google.maps.geometry.spherical.computeLength(this.line.getPath()))); const points = this.getPathPoints(); const score = this.computeScore(points); @@ -208,9 +207,8 @@ export class PathElement extends connect(store)(LitElement) { optimizedPath = [optimizedPath[1], optimizedPath[2]]; } - if (!this.optimizedLine) { - this, (this.optimizedLine = new google.maps.Polyline()); - } + this.optimizedLine ??= new google.maps.Polyline(); + this.optimizedLine.setOptions({ map: this.map, path: optimizedPath, diff --git a/apps/fxc-front/src/app/components/ui/pref-modal.ts b/apps/fxc-front/src/app/components/ui/pref-modal.ts index d544e3ca..9f01288b 100644 --- a/apps/fxc-front/src/app/components/ui/pref-modal.ts +++ b/apps/fxc-front/src/app/components/ui/pref-modal.ts @@ -4,7 +4,7 @@ import { connect } from 'pwa-helpers'; import { modalController } from '@ionic/core/components'; -import { LEAGUES } from '../../logic/score/league/leagues'; +import { LEAGUES_NAMES } from '../../logic/score/league/leagues'; import * as units from '../../logic/units'; import { setLeague } from '../../redux/planner-slice'; import { RootState, store } from '../../redux/store'; @@ -21,8 +21,8 @@ export class PrefModal extends connect(store)(LitElement) { constructor() { super(); - Object.getOwnPropertyNames(LEAGUES).forEach((value) => { - this.leagues.push({ value, name: LEAGUES[value] }); + Object.getOwnPropertyNames(LEAGUES_NAMES).forEach((value) => { + this.leagues.push({ value, name: LEAGUES_NAMES[value] }); }); this.leagues.sort((a, b) => (a < b ? -1 : 1)); } diff --git a/apps/fxc-front/src/app/logic/score/league/leagues.ts b/apps/fxc-front/src/app/logic/score/league/leagues.ts index f94f05ed..5c356614 100644 --- a/apps/fxc-front/src/app/logic/score/league/leagues.ts +++ b/apps/fxc-front/src/app/logic/score/league/leagues.ts @@ -1,10 +1,9 @@ -import { ScoringRules } from '@flyxc/optimizer'; +import { ScoringRuleNames } from '@flyxc/optimizer'; -// allowed league codes export const leagueCodes = ['czl', 'cze', 'czo', 'fr', 'leo', 'nor', 'ukc', 'uki', 'ukn', 'xc', 'xcppg', 'wxc']; export type LeagueCode = (typeof leagueCodes)[number]; -export const LEAGUES: Readonly> = { +export const LEAGUES_NAMES: Readonly> = { czl: 'Czech (ČPP local)', cze: 'Czech (ČPP Europe)', czo: 'Czech (ČPP outside Europe)', @@ -19,7 +18,7 @@ export const LEAGUES: Readonly> = { wxc: 'World XC Online Contest', }; -export function getScoringRules(league: LeagueCode): ScoringRules { +export function getScoringRules(league: LeagueCode): ScoringRuleNames { switch (league) { case 'czl': return 'CzechLocal'; diff --git a/libs/optimizer/README.md b/libs/optimizer/README.md index 7b182cde..ae736845 100644 --- a/libs/optimizer/README.md +++ b/libs/optimizer/README.md @@ -1,7 +1,5 @@ # optimizer -This library was generated with [Nx](https://nx.dev). - ## Description This library computes scores for flights using applicable rules of various XC leagues. @@ -23,10 +21,8 @@ If the `done` property is false, you should call the `next()` method again to ge See an example in `optimizer.spec.ts#expectOptimizationIsAsExpected` -## Building - -Run `nx build optimizer` to build the library. - ## Running unit tests -Run `nx test optimizer` to execute the unit tests via [Jest](https://jestjs.io). +Run `nx test optimizer`. + +This library was generated with [Nx](https://nx.dev). diff --git a/libs/optimizer/project.json b/libs/optimizer/project.json index 2f31cb68..b2bb5399 100644 --- a/libs/optimizer/project.json +++ b/libs/optimizer/project.json @@ -1,5 +1,5 @@ { - "name": "@flyxc/optimizer", + "name": "optimizer", "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "libs/optimizer/src", "projectType": "library", diff --git a/libs/optimizer/src/index.ts b/libs/optimizer/src/index.ts index 6e941aa0..eb94e615 100644 --- a/libs/optimizer/src/index.ts +++ b/libs/optimizer/src/index.ts @@ -1,3 +1,3 @@ export { getOptimizer, CircuitType } from './lib/optimizer'; export type { LatLonAltTime, ScoringTrack, OptimizationResult, OptimizationRequest } from './lib/optimizer'; -export type { ScoringRules } from './lib/scoringRules'; +export type { ScoringRuleNames } from './lib/scoringRules'; diff --git a/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts b/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts index 99edf55c..d553a1de 100644 --- a/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts +++ b/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts @@ -2,7 +2,7 @@ import { OptimizationRequest, OptimizationResult, CircuitType } from '../optimiz import { computeDestinationPoint, getGreatCircleBearing, getPreciseDistance } from 'geolib'; import { createSegments } from '../utils/createSegments'; import { mergeTracks } from '../utils/mergeTracks'; -import { ScoringRules } from '../scoringRules'; +import { ScoringRuleNames } from '../scoringRules'; /** * Functions to generate test fixtures for the optimizer tests @@ -15,7 +15,7 @@ import { ScoringRules } from '../scoringRules'; */ export type OptimizerFixture = { request: OptimizationRequest; - rules: ScoringRules; + rules: ScoringRuleNames; expectedResult: Omit; }; @@ -55,7 +55,7 @@ export function createFreeDistanceFixture( from: LatLon, to: LatLon, nbSegments: number, - givenRules: ScoringRules, + givenRules: ScoringRuleNames, ): OptimizerFixture { const multiplier = getFreeDistanceMultiplier(givenRules); const distance = getPreciseDistance(from, to) / 1000; @@ -93,7 +93,7 @@ export function createFreeDistance1PointFixture( intermediate: LatLon, to: LatLon, nbSegments: number, - givenRules: ScoringRules, + givenRules: ScoringRuleNames, ): OptimizerFixture { const distance = (getPreciseDistance(from, intermediate) + getPreciseDistance(intermediate, to)) / 1000; const multiplier = getFreeDistanceMultiplier(givenRules); @@ -141,7 +141,7 @@ export function createFreeDistance2PointsFixture( turnPoint2: LatLon, to: LatLon, nbSegments: number, - givenRules: ScoringRules, + givenRules: ScoringRuleNames, ): OptimizerFixture { const distance = (getPreciseDistance(from, turnPoint1) + @@ -201,7 +201,7 @@ export function createFreeDistance3PointsFixture( turnPoint3: LatLon, to: LatLon, nbSegments: number, - givenRules: ScoringRules, + givenRules: ScoringRuleNames, ): OptimizerFixture { const distance = (getPreciseDistance(from, turnPoint1) + @@ -264,7 +264,7 @@ export function createClosedFlatTriangleFixture( turnPoint1: LatLon, turnPoint2: LatLon, nbSegments: number, - givenRules: ScoringRules, + givenRules: ScoringRuleNames, ): OptimizerFixture { if (isFAI(start, turnPoint1, turnPoint2)) { throw new Error('invalid test data: not a flat triangle'); @@ -295,7 +295,7 @@ export function createClosedFaiTriangleFixture( start: LatLon, turnPoint1: LatLon, nbSegments: number, - givenRules: ScoringRules, + givenRules: ScoringRuleNames, ): OptimizerFixture { const distance1 = getPreciseDistance(start, turnPoint1); const bearingStartToP1 = getGreatCircleBearing(start, turnPoint1); @@ -316,7 +316,7 @@ export function createClosedFaiTriangleFixtureWithSmallCycle( start: LatLon, p1: LatLon, nbIntervals: number, - givenRules: ScoringRules, + givenRules: ScoringRuleNames, ): OptimizerFixture { const standardFixture = createClosedFaiTriangleFixture(start, p1, nbIntervals, givenRules); return { @@ -336,7 +336,7 @@ export function createClosedFaiTriangleFixtureWithSmallLoop( start: LatLon, p1: LatLon, nbIntervals: number, - givenRules: ScoringRules, + givenRules: ScoringRuleNames, ): OptimizerFixture { const standardFixture = createClosedFaiTriangleFixture(start, p1, nbIntervals, givenRules); return { @@ -349,7 +349,7 @@ export function createClosedFaiTriangleFixtureWithSmallLoop( }; } -function getFreeDistanceMultiplier(scoringRules: ScoringRules) { +function getFreeDistanceMultiplier(scoringRules: ScoringRuleNames) { switch (scoringRules) { case 'CzechLocal': case 'CzechEuropean': @@ -369,7 +369,7 @@ function getFreeDistanceMultiplier(scoringRules: ScoringRules) { } } -function getFlatTriangleMultiplier(scoringRules: ScoringRules) { +function getFlatTriangleMultiplier(scoringRules: ScoringRuleNames) { switch (scoringRules) { case 'CzechEuropean': case 'CzechOutsideEurope': @@ -392,7 +392,7 @@ function getFlatTriangleMultiplier(scoringRules: ScoringRules) { } } -function getFaiTriangleMultiplier(scoringRules: ScoringRules) { +function getFaiTriangleMultiplier(scoringRules: ScoringRuleNames) { switch (scoringRules) { case 'CzechEuropean': case 'CzechOutsideEurope': @@ -431,7 +431,7 @@ function createTriangleFixture( p1: LatLon, p2: { lon: number; lat: number }, nbSegments: number, - givenRules: ScoringRules, + givenRules: ScoringRuleNames, multiplier: number, circuit: CircuitType, ): OptimizerFixture { diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index 56725acd..9ea059d5 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -1,21 +1,12 @@ -import { Solution, solver } from 'igc-xc-score'; +// TODO: all console logs are commented out. In the future, we should use a logging library + +import { solver, Solution } from 'igc-xc-score'; import { BRecord, IGCFile } from 'igc-parser'; -import { createSegments } from './utils/createSegments'; -import { mergeTracks } from './utils/mergeTracks'; -import { ScoringRules, scoringRules } from './scoringRules'; -import { getDistance } from 'geolib'; +import { ScoringRuleNames, scoringRules } from './scoringRules'; -// When the track has not enough points (<5), we build a new one by adding interpolated points between existing ones. +// Minimum number of points in an igc-xc-score track. // See this issue https://github.com/mmomtchev/igc-xc-score/issues/231 -const MIN_POINTS = 5; -const NUM_SEGMENTS_BETWEEN_POINTS = 2; - -// For adding interpolated points, this constant adjusts the proximity of the points to the starting point of -// the segment. We want the added points to be very close to the starting points of the segment so that the solution -// points returned by the solver are as close as possible (or may be equal) to one of the original points of the track. -const DISTRIBUTION_FACTOR_FOR_ADDED_POINTS = 1e-5; - -// TODO: all console.xxx statements are commented. In the future, we should use a logging library +const MIN_IGC_XC_SCORE_POINTS = 5; export interface LatLonAltTime { alt: number; @@ -95,15 +86,15 @@ export interface OptimizationResult { * * At each iteration, the score should be a better solutions. * - * @param request the OptimizationRequest. if request.options is undefined, then there will be one iteration, and the result - * will be the best solution - * @param rules the ScoringRules to apply for computation - * @return an Iterator of OptimizationResult * @see README.md + * + * @param request Contains the tracks and options. + * @param rules The ScoringRules to use. + * @return an Iterator of OptimizationResult */ export function* getOptimizer( request: OptimizationRequest, - rules: ScoringRules, + rules: ScoringRuleNames, ): Iterator { if (request.track.points.length == 0) { // console.warn('Empty track received in optimization request. Returns a 0 score'); @@ -116,46 +107,41 @@ export function* getOptimizer( }; } const originalTrack = request.track; - const solverTrack = buildValidTrackForSolver(originalTrack); + const solverTrack = appendPointsIfNeeded(originalTrack, MIN_IGC_XC_SCORE_POINTS); const flight = toIgcFile(solverTrack); const solverScoringRules = scoringRules.get(rules); - const options = toSolverOptions(request.options); + const options = toSolverOptions(request); const solutionIterator = solver(flight, solverScoringRules || {}, options); while (true) { const solution = solutionIterator.next(); if (solution.done) { // console.debug('solution', JSON.stringify(solution.value, undefined, 2)); - return toOptimizationResult(solution.value, originalTrack, solverTrack); + return toOptimizationResult(solution.value, originalTrack); } - yield toOptimizationResult(solution.value, originalTrack, solverTrack); + yield toOptimizationResult(solution.value, originalTrack); } } /** - * the solver requires at least 5 points, so if there is not enough points, - * we create points between existing ones + * Append points if the track is too short for igc-xc-score. + * + * The points are close enough to the last point to not affect the score. */ -function buildValidTrackForSolver(track: ScoringTrack) { - if (track.points.length >= MIN_POINTS) { +function appendPointsIfNeeded(track: ScoringTrack, minValidLength: number) { + if (track.points.length >= minValidLength) { return track; } - // console.debug(`not enough points (${track.points.length}) in track. Interpolate intermediate points`); - track = deepCopy(track); - while (track.points.length < MIN_POINTS) { - const segments: ScoringTrack[] = []; - for (let i = 1; i < track.points.length; i++) { - // split each segment of the track into two segments - segments.push( - createSegments( - track.points[i - 1], - track.points[i], - track.startTimeSec, - NUM_SEGMENTS_BETWEEN_POINTS, - DISTRIBUTION_FACTOR_FOR_ADDED_POINTS, - ), - ); - } - track = mergeTracks(...segments); + + // console.debug(`The track is too short, appending (${MIN_IGC_XC_SCORE_POINTS - track.points.length}) points`); + + track = JSON.parse(JSON.stringify(track)); + while (track.points.length < minValidLength) { + const lastPoint = track.points.at(-1); + track.points.push({ + ...lastPoint, + lat: lastPoint.lat + 0.000001, + offsetFromStartSec: lastPoint.offsetFromStartSec + 60, + }); } // console.debug(`new track has ${newTrack.points.length} points`); return track; @@ -181,45 +167,34 @@ function toIgcFile(track: ScoringTrack): IGCFile { enl: null, }; }); - // we ignore some properties of the igc-file, as they are not required for the computation - // @ts-ignore + + // Only fill out the fields required by igc-xc-score. return { date: new Date(track.startTimeSec * 1000).toISOString(), fixes: fixes, - }; + } as any; } -type SolverOptions = { maxloop?: number; maxcycle?: number }; - -function toSolverOptions(request: OptimizationRequest): SolverOptions { +function toSolverOptions(request: OptimizationRequest) { + // TODO: upstream the type to igc-xc-score return { maxcycle: request.maxCycleDurationMs, maxloop: request.maxNumCycles, }; } -function toOptimizationResult( - solution: Solution, - originalTrack: ScoringTrack, - solverTrack: ScoringTrack, -): OptimizationResult { +function toOptimizationResult(solution: Solution, originalTrack: ScoringTrack): OptimizationResult { return { score: solution.score ?? 0, lengthKm: solution.scoreInfo?.distance ?? 0, multiplier: solution.opt.scoring.multiplier, circuit: toCircuitType(solution.opt.scoring.code), closingRadiusM: getClosingRadiusM(solution), - solutionIndices: getIndices(solution, originalTrack, solverTrack), + solutionIndices: getSolutionIndices(solution, originalTrack), optimal: solution.optimal || false, }; } -// TODO: submit a PR to igc-xc-score -interface Scoring { - closingDistanceFixed?: number; - closingDistanceRelative?: number; -} - function getClosingRadiusM(solution: Solution): number | undefined { const closingDistance = solution.scoreInfo?.cp?.d; @@ -227,13 +202,15 @@ function getClosingRadiusM(solution: Solution): number | undefined { return undefined; } - const closingDistanceFixed = solution.opt.scoring?.closingDistanceFixed; + // TODO: remove cast when https://github.com/mmomtchev/igc-xc-score/pull/233 is merged + const closingDistanceFixed = (solution.opt.scoring as any)?.closingDistanceFixed; if (closingDistanceFixed != null && closingDistance < closingDistanceFixed) { - return closingDistanceFixed; + return closingDistanceFixed * 1000; } - const closingDistanceRelativeRatio = solution.opt.scoring?.closingDistanceRelative; + // TODO: remove cast when https://github.com/mmomtchev/igc-xc-score/pull/233 is merged + const closingDistanceRelativeRatio = (solution.opt.scoring as any)?.closingDistanceRelative; const closingDistanceRelative = solution.scoreInfo?.distance != null && closingDistanceRelativeRatio != null ? closingDistanceRelativeRatio * solution.scoreInfo.distance @@ -246,9 +223,6 @@ function getClosingRadiusM(solution: Solution): number | undefined { return undefined; } -const circuitTypeCodes = ['od', 'tri', 'fai', 'oar']; -type CircuitTypeCode = (typeof circuitTypeCodes)[number]; - const circuitMapping = { od: CircuitType.OpenDistance, tri: CircuitType.FlatTriangle, @@ -265,9 +239,7 @@ function toCircuitType(code: string): CircuitType { } /** - * Return the indices of the solution points. - * - * This permit to identify the solution points in the ScoringTrack.points array + * Return the indices of the solution in the input track. * * It contains (when applicable): * - the starting point @@ -276,73 +248,17 @@ function toCircuitType(code: string): CircuitType { * - the 'out' closing point * - the end point * */ -function getIndices(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack) { - const result: number[] = []; - pushInResult(getEntryPointsStartIndex(solution, originalTrack, solverTrack)); - pushInResult(getClosingPointsInIndex(solution, originalTrack, solverTrack)); - solution.scoreInfo?.tp - ?.map((turnPoint) => turnPoint.r) - .forEach((index) => pushInResult(getPointIndex(index, originalTrack, solverTrack))); - pushInResult(getClosingPointsOutIndex(solution, originalTrack, solverTrack)); - pushInResult(getEntryPointsFinishIndex(solution, originalTrack, solverTrack)); - return result; - - function pushInResult(index: number) { - if (index >= 0) { - result.push(index); - } - } -} - -function getEntryPointsStartIndex(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { - // console.debug('getEntryPointsStartIndex', solution.scoreInfo?.ep?.start.r); - return getPointIndex(solution.scoreInfo?.ep?.start.r, originalTrack, solverTrack); -} - -function getClosingPointsInIndex(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { - // console.debug('getClosingPointsInIndex', solution.scoreInfo?.cp?.in.r); - return getPointIndex(solution.scoreInfo?.cp?.in.r, originalTrack, solverTrack); -} - -function getClosingPointsOutIndex(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { - // console.debug('getClosingPointsOutIndex', solution.scoreInfo?.cp?.out.r); - return getPointIndex(solution.scoreInfo?.cp?.out.r, originalTrack, solverTrack); -} - -function getEntryPointsFinishIndex(solution: Solution, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { - // console.debug('getEntryPointsFinishIndex', solution.scoreInfo?.ep?.finish.r); - return getPointIndex(solution.scoreInfo?.ep?.finish.r, originalTrack, solverTrack); -} - -function getPointIndex(index: number | undefined, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { - if (index === undefined) { - return -1; - } - return solutionContainsValidIndices(originalTrack, solverTrack) - ? index - : getIndexInOriginalTrack(index, originalTrack, solverTrack); -} - -function solutionContainsValidIndices(originalTrack: ScoringTrack, solverTrack: ScoringTrack): boolean { - return originalTrack.points.length === solverTrack.points.length; -} - -function getIndexInOriginalTrack(index: number, originalTrack: ScoringTrack, solverTrack: ScoringTrack): number { - const solutionPoint = solverTrack.points[index]; - let indexInOriginalTrack = -1; - let closestDistance = Number.MAX_VALUE; - for (let i = 0; i < originalTrack.points.length; i++) { - const point = originalTrack.points[i]; - const distance = getDistance(point, solutionPoint); - if (distance < closestDistance) { - closestDistance = distance; - indexInOriginalTrack = i; - } - } - return indexInOriginalTrack; -} - -// Not the most performant solution but is used only for slow dimension problems -function deepCopy(source: T): T { - return JSON.parse(JSON.stringify(source)); +function getSolutionIndices(solution: Solution, inputTrack: ScoringTrack): number[] { + return ( + [ + solution.scoreInfo?.ep?.start.r, + solution.scoreInfo?.cp?.in.r, + ...(solution.scoreInfo?.tp ?? []).map((turnPoint) => turnPoint.r), + solution.scoreInfo?.cp?.out.r, + solution.scoreInfo?.ep?.finish.r, + ] + .filter((index) => index != null) + // Map added dummy points back to the last point of the input track. + .map((index) => Math.min(index, inputTrack.points.length - 1)) + ); } diff --git a/libs/optimizer/src/lib/scoringRules.ts b/libs/optimizer/src/lib/scoringRules.ts index 3a01dcfb..6171a56a 100644 --- a/libs/optimizer/src/lib/scoringRules.ts +++ b/libs/optimizer/src/lib/scoringRules.ts @@ -1,5 +1,6 @@ -import { scoringRules as xcScoreRules } from 'igc-xc-score'; +import * as igcXcScore from 'igc-xc-score'; +// TODO: this should be `keyof typeof igcXcScore.scoringRules` if the types were correct export const scoringRulesNames = [ 'CzechLocal', 'CzechEuropean', @@ -13,14 +14,16 @@ export const scoringRulesNames = [ 'XContest', 'XContestPPG', 'WorldXC', -]; -export type ScoringRules = (typeof scoringRulesNames)[number]; +] as const; + +export type ScoringRuleNames = (typeof scoringRulesNames)[number]; -const scoringBaseModel = xcScoreRules['XContest']; +// TODO: Export the rules from igc-xc-score +const scoringBaseModel = igcXcScore.scoringRules['XContest']; const openDistanceBase = scoringBaseModel[0]; const freeTriangleBase = scoringBaseModel[1]; const faiTriangleBase = scoringBaseModel[2]; -const outAndReturnBase = xcScoreRules['FAI-OAR'][0]; +const outAndReturnBase = igcXcScore.scoringRules['FAI-OAR'][0]; const czechLocalRule = [ { ...openDistanceBase, multiplier: 1 }, @@ -96,17 +99,17 @@ const wxcRule = [ { ...faiTriangleBase, multiplier: 2, closingDistanceFixed: 0.2 }, ]; -export const scoringRules: Map = new Map([ +export const scoringRules: Map = new Map([ ['CzechEuropean', czechEuropeRule], ['CzechLocal', czechLocalRule], ['CzechOutsideEurope', czechOutEuropeRule], - ['FederationFrancaiseVolLibre', xcScoreRules['FFVL']], + ['FederationFrancaiseVolLibre', igcXcScore.scoringRules['FFVL']], ['Leonardo', leonardoRule], ['Norway', norwayRule], ['UnitedKingdomClub', ukXclClubRule], ['UnitedKingdomInternational', ukXclInternationalRule], ['UnitedKingdomNational', ukXclNationalRule], - ['XContest', xcScoreRules['XContest']], + ['XContest', igcXcScore.scoringRules['XContest']], ['XContestPPG', xContestPpgRule], ['WorldXC', wxcRule], ]); From 0090f1c7a840e074426d74440f75e5965dc1115d Mon Sep 17 00:00:00 2001 From: flyingtof Date: Fri, 31 May 2024 14:07:02 +0200 Subject: [PATCH 05/20] fix: compilation issues --- libs/optimizer/src/lib/optimizer.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index 9ea059d5..d92ca593 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -136,7 +136,7 @@ function appendPointsIfNeeded(track: ScoringTrack, minValidLength: number) { track = JSON.parse(JSON.stringify(track)); while (track.points.length < minValidLength) { - const lastPoint = track.points.at(-1); + const lastPoint = track.points.at(-1)!; track.points.push({ ...lastPoint, lat: lastPoint.lat + 0.000001, @@ -231,7 +231,7 @@ const circuitMapping = { }; function toCircuitType(code: string): CircuitType { - const type = circuitMapping[code]; + const type = circuitMapping[code as 'od' | 'tri' | 'fai' | 'oar']; if (type == null) { throw new Error(`Unknown type "${code}"`); } @@ -259,6 +259,6 @@ function getSolutionIndices(solution: Solution, inputTrack: ScoringTrack): numbe ] .filter((index) => index != null) // Map added dummy points back to the last point of the input track. - .map((index) => Math.min(index, inputTrack.points.length - 1)) + .map((index) => Math.min(index!, inputTrack.points.length - 1)) ); } From 843a1c4df4578d3a2d5fa96a7f551cddffff8f30 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Fri, 31 May 2024 15:46:09 +0200 Subject: [PATCH 06/20] tweaks part 3 --- docker/docker-compose.yml | 1 - libs/optimizer/src/index.ts | 2 +- .../src/lib/fixtures/optimizer.fixtures.ts | 7 +++--- libs/optimizer/src/lib/optimizer.spec.ts | 2 +- libs/optimizer/src/lib/optimizer.ts | 2 +- .../lib/{scoringRules.ts => scoring-rules.ts} | 0 .../{createSegments.ts => create-segments.ts} | 0 libs/optimizer/src/lib/utils/merge-tracks.ts | 25 +++++++++++++++++++ libs/optimizer/src/lib/utils/mergeTracks.ts | 23 ----------------- tsconfig.base.json | 2 +- 10 files changed, 33 insertions(+), 31 deletions(-) rename libs/optimizer/src/lib/{scoringRules.ts => scoring-rules.ts} (100%) rename libs/optimizer/src/lib/utils/{createSegments.ts => create-segments.ts} (100%) create mode 100644 libs/optimizer/src/lib/utils/merge-tracks.ts delete mode 100644 libs/optimizer/src/lib/utils/mergeTracks.ts diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 9945240f..52b629c9 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,7 +1,6 @@ # This file permits to launch docker images of services required for this app # services: - # launch it with ' docker compose up -d redis' redis: image: redis:latest diff --git a/libs/optimizer/src/index.ts b/libs/optimizer/src/index.ts index eb94e615..e1c361ad 100644 --- a/libs/optimizer/src/index.ts +++ b/libs/optimizer/src/index.ts @@ -1,3 +1,3 @@ export { getOptimizer, CircuitType } from './lib/optimizer'; export type { LatLonAltTime, ScoringTrack, OptimizationResult, OptimizationRequest } from './lib/optimizer'; -export type { ScoringRuleNames } from './lib/scoringRules'; +export type { ScoringRuleNames } from './lib/scoring-rules'; diff --git a/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts b/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts index d553a1de..d9ae93fa 100644 --- a/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts +++ b/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts @@ -1,8 +1,8 @@ import { OptimizationRequest, OptimizationResult, CircuitType } from '../optimizer'; import { computeDestinationPoint, getGreatCircleBearing, getPreciseDistance } from 'geolib'; -import { createSegments } from '../utils/createSegments'; -import { mergeTracks } from '../utils/mergeTracks'; -import { ScoringRuleNames } from '../scoringRules'; +import { createSegments } from '../utils/create-segments'; +import { mergeTracks } from '../utils/merge-tracks'; +import { ScoringRuleNames } from '../scoring-rules'; /** * Functions to generate test fixtures for the optimizer tests @@ -44,6 +44,7 @@ export type LatLon = { }; const START_TIME_SEC = Math.round(new Date().getTime() / 1000); + /** * @param from LatLon of the starting point * @param to LatLon of the ending point diff --git a/libs/optimizer/src/lib/optimizer.spec.ts b/libs/optimizer/src/lib/optimizer.spec.ts index 447c3888..4b59b037 100644 --- a/libs/optimizer/src/lib/optimizer.spec.ts +++ b/libs/optimizer/src/lib/optimizer.spec.ts @@ -11,7 +11,7 @@ import { createFreeDistanceFixture, OptimizerFixture, } from './fixtures/optimizer.fixtures'; -import { scoringRulesNames } from './scoringRules'; +import { scoringRulesNames } from './scoring-rules'; describe('optimizer', () => { describe('given an empty request', () => { diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index d92ca593..33ad5c92 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -2,7 +2,7 @@ import { solver, Solution } from 'igc-xc-score'; import { BRecord, IGCFile } from 'igc-parser'; -import { ScoringRuleNames, scoringRules } from './scoringRules'; +import { ScoringRuleNames, scoringRules } from './scoring-rules'; // Minimum number of points in an igc-xc-score track. // See this issue https://github.com/mmomtchev/igc-xc-score/issues/231 diff --git a/libs/optimizer/src/lib/scoringRules.ts b/libs/optimizer/src/lib/scoring-rules.ts similarity index 100% rename from libs/optimizer/src/lib/scoringRules.ts rename to libs/optimizer/src/lib/scoring-rules.ts diff --git a/libs/optimizer/src/lib/utils/createSegments.ts b/libs/optimizer/src/lib/utils/create-segments.ts similarity index 100% rename from libs/optimizer/src/lib/utils/createSegments.ts rename to libs/optimizer/src/lib/utils/create-segments.ts diff --git a/libs/optimizer/src/lib/utils/merge-tracks.ts b/libs/optimizer/src/lib/utils/merge-tracks.ts new file mode 100644 index 00000000..077d31bb --- /dev/null +++ b/libs/optimizer/src/lib/utils/merge-tracks.ts @@ -0,0 +1,25 @@ +import { LatLonAltTime, ScoringTrack } from '../optimizer'; + +/** + * Merge multiple tracks. + * + * Collapse end and start point of consecutive tracks when they match. + * + * @param tracks the tracks to concatenate + * @return a track + */ +export function mergeTracks(...tracks: ScoringTrack[]): ScoringTrack { + const points: LatLonAltTime[] = []; + + for (const track of tracks) { + if (track.points.length == 0) { + continue; + } + const collapse = points.at(-1)?.lat === track.points[0].lat && points.at(-1)?.lon === track.points[0].lon; + points.push(...(collapse ? track.points.slice(1) : track.points)); + } + return { + points, + startTimeSec: 0, + }; +} diff --git a/libs/optimizer/src/lib/utils/mergeTracks.ts b/libs/optimizer/src/lib/utils/mergeTracks.ts deleted file mode 100644 index 93278c3e..00000000 --- a/libs/optimizer/src/lib/utils/mergeTracks.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ScoringTrack } from '../optimizer'; - -/** - * merge multiple tracks into one track. - * it removes duplicated points between each end and start of consecutive tracks - * @param tracks the tracks to concatenate - * @return a track - */ -export function mergeTracks(...tracks: ScoringTrack[]): ScoringTrack { - const concatenated: ScoringTrack = { - points: [], - startTimeSec: 0, - }; - - for (const track of tracks) { - const skipFirstPoint = - concatenated.points.at(-1)?.lat === track.points[0].lat && - concatenated.points.at(-1)?.lon === track.points[0].lon; - const arrayToConcat = skipFirstPoint ? track.points.slice(1) : track.points; - concatenated.points = concatenated.points.concat(arrayToConcat); - } - return concatenated; -} diff --git a/tsconfig.base.json b/tsconfig.base.json index 123b7cfa..fec0118f 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -20,7 +20,7 @@ "@flyxc/common-node": ["libs/common-node/src/index.ts"], "@flyxc/optimizer": ["libs/optimizer/src/index.ts"], "@vaadin/dom": ["libs/vaadin-dom/src/index.ts"], - "@vaadin/nodom": ["libs/vaadin-nodom/src/index.ts"], + "@vaadin/nodom": ["libs/vaadin-nodom/src/index.ts"] } }, "exclude": ["node_modules", "tmp"] From 8f6fec2888cf4b6e43178c5c71f0ea8ab8c185ab Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Fri, 31 May 2024 17:59:06 +0200 Subject: [PATCH 07/20] tweaks --- .../src/app/components/2d/path-element.ts | 21 +- .../src/app/components/ui/pref-modal.ts | 6 +- .../src/app/logic/score/league/leagues.ts | 83 ++- apps/fxc-front/src/app/redux/planner-slice.ts | 7 +- apps/fxc-front/vite.config.ts | 2 +- libs/optimizer/src/index.ts | 4 +- .../src/lib/fixtures/optimizer.fixtures.ts | 476 ------------------ libs/optimizer/src/lib/optimizer.spec.ts | 391 +++++++++----- libs/optimizer/src/lib/optimizer.ts | 44 +- libs/optimizer/src/lib/scoring-rules.ts | 123 +++-- .../src/lib/utils/create-segments.ts | 57 +-- libs/optimizer/src/lib/utils/merge-tracks.ts | 5 +- 12 files changed, 430 insertions(+), 789 deletions(-) delete mode 100644 libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts diff --git a/apps/fxc-front/src/app/components/2d/path-element.ts b/apps/fxc-front/src/app/components/2d/path-element.ts index ad542f65..deeeb9f2 100644 --- a/apps/fxc-front/src/app/components/2d/path-element.ts +++ b/apps/fxc-front/src/app/components/2d/path-element.ts @@ -17,8 +17,9 @@ import { Score } from '../../logic/score/scorer'; import { setDistance, setEnabled, setRoute, setScore } from '../../redux/planner-slice'; import { RootState, store } from '../../redux/store'; import { PlannerElement } from './planner-element'; -import { CircuitType, getOptimizer, ScoringTrack } from '@flyxc/optimizer'; -import { getScoringRules } from '../../logic/score/league/leagues'; +import { CircuitType, getOptimizer } from '@flyxc/optimizer'; +import { getScoringRuleName } from '../../logic/score/league/leagues'; +import type { LeagueCode } from '../../logic/score/league/leagues'; // Route color by circuit type. const ROUTE_STROKE_COLORS = { @@ -44,7 +45,7 @@ export class PathElement extends connect(store)(LitElement) { @state() private enabled = false; @state() - private league = 'xc'; + private league: LeagueCode = 'xc'; @state() private encodedRoute = ''; @state() @@ -191,10 +192,11 @@ export class PathElement extends connect(store)(LitElement) { // Optimize the route and draw the optimize lines and sectors. private optimize(): void { - if (!this.line || this.line.getPath().getLength() < 2 || this.doNotSyncState) { + const { line } = this; + if (!line || line.getPath().getLength() < 2 || this.doNotSyncState) { return; } - store.dispatch(setDistance(google.maps.geometry.spherical.computeLength(this.line.getPath()))); + store.dispatch(setDistance(google.maps.geometry.spherical.computeLength(line.getPath()))); const points = this.getPathPoints(); const score = this.computeScore(points); @@ -249,12 +251,11 @@ export class PathElement extends connect(store)(LitElement) { } private computeScore(points: LatLon[]): Score { - const track: ScoringTrack = { - points: points.map((point, i) => ({ ...point, alt: 0, offsetFromStartSec: i * 60 })), - startTimeSec: Math.round(new Date().getTime() / 1000), - }; // TODO: limit the processing time ? - const result = getOptimizer({ track }, getScoringRules(this.league)).next().value; + const result = getOptimizer( + { track: { points: points.map((point, i) => ({ ...point, alt: 0, timeSec: i * 60 })) } }, + getScoringRuleName(this.league), + ).next().value; return new Score({ circuit: result.circuit, distanceM: result.lengthKm * 1000, diff --git a/apps/fxc-front/src/app/components/ui/pref-modal.ts b/apps/fxc-front/src/app/components/ui/pref-modal.ts index 9f01288b..8b1070d1 100644 --- a/apps/fxc-front/src/app/components/ui/pref-modal.ts +++ b/apps/fxc-front/src/app/components/ui/pref-modal.ts @@ -4,11 +4,11 @@ import { connect } from 'pwa-helpers'; import { modalController } from '@ionic/core/components'; -import { LEAGUES_NAMES } from '../../logic/score/league/leagues'; import * as units from '../../logic/units'; import { setLeague } from '../../redux/planner-slice'; import { RootState, store } from '../../redux/store'; import { setAltitudeUnit, setDistanceUnit, setSpeedUnit, setVarioUnit } from '../../redux/units-slice'; +import { LEAGUE_CODES, LEAGUES } from '../../logic/score/league/leagues'; @customElement('pref-modal') export class PrefModal extends connect(store)(LitElement) { @@ -21,8 +21,8 @@ export class PrefModal extends connect(store)(LitElement) { constructor() { super(); - Object.getOwnPropertyNames(LEAGUES_NAMES).forEach((value) => { - this.leagues.push({ value, name: LEAGUES_NAMES[value] }); + LEAGUE_CODES.forEach((value) => { + this.leagues.push({ value, name: LEAGUES[value].name }); }); this.leagues.sort((a, b) => (a < b ? -1 : 1)); } diff --git a/apps/fxc-front/src/app/logic/score/league/leagues.ts b/apps/fxc-front/src/app/logic/score/league/leagues.ts index 5c356614..7ccebba2 100644 --- a/apps/fxc-front/src/app/logic/score/league/leagues.ts +++ b/apps/fxc-front/src/app/logic/score/league/leagues.ts @@ -1,49 +1,46 @@ -import { ScoringRuleNames } from '@flyxc/optimizer'; +import { ScoringRuleName } from '@flyxc/optimizer'; -export const leagueCodes = ['czl', 'cze', 'czo', 'fr', 'leo', 'nor', 'ukc', 'uki', 'ukn', 'xc', 'xcppg', 'wxc']; -export type LeagueCode = (typeof leagueCodes)[number]; +export const LEAGUE_CODES = [ + 'czl', + 'cze', + 'czo', + 'fr', + 'leo', + 'nor', + 'ukc', + 'uki', + 'ukn', + 'xc', + 'xcppg', + 'wxc', +] as const; -export const LEAGUES_NAMES: Readonly> = { - czl: 'Czech (ČPP local)', - cze: 'Czech (ČPP Europe)', - czo: 'Czech (ČPP outside Europe)', - fr: 'France (CFD)', - leo: 'Leonardo', - nor: 'Norway (Distanseligaen)', - ukc: 'UK (XC League, Club)', - uki: 'UK (XC League, International)', - ukn: 'UK (XC League, National)', - xc: 'XContest', - xcppg: 'XContest PPG', - wxc: 'World XC Online Contest', +export type LeagueCode = (typeof LEAGUE_CODES)[number]; + +interface LeagueDetails { + name: string; + ruleName: ScoringRuleName; +} + +export const LEAGUES: Readonly> = { + czl: { name: 'Czech (ČPP local)', ruleName: 'CzechLocal' }, + cze: { name: 'Czech (ČPP Europe)', ruleName: 'CzechEurope' }, + czo: { name: 'Czech (ČPP outside Europe)', ruleName: 'CzechOutsideEurope' }, + fr: { name: 'France (CFD)', ruleName: 'FFVL' }, + leo: { name: 'Leonardo', ruleName: 'Leonardo' }, + nor: { name: 'Norway (Distanseligaen)', ruleName: 'Norway' }, + ukc: { name: 'UK (XC League, Club)', ruleName: 'UKClub' }, + uki: { name: 'UK (XC League, International)', ruleName: 'UKInternational' }, + ukn: { name: 'UK (XC League, National)', ruleName: 'UKNational' }, + xc: { name: 'XContest', ruleName: 'XContest' }, + xcppg: { name: 'XContest PPG', ruleName: 'XContestPPG' }, + wxc: { name: 'World XC Online Contest', ruleName: 'WorldXC' }, }; -export function getScoringRules(league: LeagueCode): ScoringRuleNames { - switch (league) { - case 'czl': - return 'CzechLocal'; - case 'cze': - return 'CzechEuropean'; - case 'czo': - return 'CzechOutsideEurope'; - case 'fr': - return 'FederationFrancaiseVolLibre'; - case 'leo': - return 'Leonardo'; - case 'nor': - return 'Norway'; - case 'ukc': - return 'UnitedKingdomClub'; - case 'uki': - return 'UnitedKingdomInternational'; - case 'ukn': - return 'UnitedKingdomNational'; - case 'xc': - return 'XContest'; - case 'xcppg': - return 'XContestPPG'; - case 'wxc': - return 'WorldXC'; +export function getScoringRuleName(leagueCode: LeagueCode): ScoringRuleName { + const ruleName = LEAGUES[leagueCode]?.ruleName; + if (ruleName == null) { + throw new Error('Unkown league code "${leagueCode}"'); } - throw Error('no corresponding rule for ' + league); + return ruleName; } diff --git a/apps/fxc-front/src/app/redux/planner-slice.ts b/apps/fxc-front/src/app/redux/planner-slice.ts index 5b3a4a85..1e80905c 100644 --- a/apps/fxc-front/src/app/redux/planner-slice.ts +++ b/apps/fxc-front/src/app/redux/planner-slice.ts @@ -2,12 +2,13 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { deleteUrlParam, getUrlParamValues, ParamNames, setUrlParamValue } from '../logic/history'; import { Score } from '../logic/score/scorer'; +import { LeagueCode } from '../logic/score/league/leagues'; export type PlannerState = { score?: Score; speed: number; distance: number; - league: string; + league: LeagueCode; enabled: boolean; // Encoded route. route: string; @@ -21,7 +22,7 @@ const initialState: PlannerState = { score: undefined, speed: Number(getUrlParamValues(ParamNames.speed)[0] ?? 20), distance: 0, - league: getUrlParamValues(ParamNames.league)[0] ?? localStorage.getItem('league') ?? 'xc', + league: (getUrlParamValues(ParamNames.league)[0] ?? localStorage.getItem('league') ?? 'xc') as LeagueCode, enabled, route, isFreeDrawing: false, @@ -41,7 +42,7 @@ const plannerSlice = createSlice({ state.speed = Math.max(1, action.payload); setUrlParamValue(ParamNames.speed, state.speed.toFixed(1)); }, - setLeague: (state, action: PayloadAction) => { + setLeague: (state, action: PayloadAction) => { setUrlParamValue(ParamNames.league, action.payload); localStorage.setItem('league', action.payload); state.league = action.payload; diff --git a/apps/fxc-front/vite.config.ts b/apps/fxc-front/vite.config.ts index fec8334f..0ef2fcbd 100644 --- a/apps/fxc-front/vite.config.ts +++ b/apps/fxc-front/vite.config.ts @@ -93,7 +93,7 @@ export default defineConfig({ define: { __BUILD_TIMESTAMP__: JSON.stringify(format(new Date(), 'yyyyMMdd.HHmm')), __AIRSPACE_DATE__: JSON.stringify(getAirspaceDate()), - // required by igc-xc-score. TODO(vicb): check how to remove this + // TODO(vicb): check how to remove this (igc-xc-score) global: {}, }, }); diff --git a/libs/optimizer/src/index.ts b/libs/optimizer/src/index.ts index e1c361ad..6c2c19f4 100644 --- a/libs/optimizer/src/index.ts +++ b/libs/optimizer/src/index.ts @@ -1,3 +1,3 @@ export { getOptimizer, CircuitType } from './lib/optimizer'; -export type { LatLonAltTime, ScoringTrack, OptimizationResult, OptimizationRequest } from './lib/optimizer'; -export type { ScoringRuleNames } from './lib/scoring-rules'; +export type { LatLonAltTime, ScoringTrack, ScoringResult, ScoringRequest } from './lib/optimizer'; +export type { ScoringRuleName, scoringRuleNames } from './lib/scoring-rules'; diff --git a/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts b/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts deleted file mode 100644 index d9ae93fa..00000000 --- a/libs/optimizer/src/lib/fixtures/optimizer.fixtures.ts +++ /dev/null @@ -1,476 +0,0 @@ -import { OptimizationRequest, OptimizationResult, CircuitType } from '../optimizer'; -import { computeDestinationPoint, getGreatCircleBearing, getPreciseDistance } from 'geolib'; -import { createSegments } from '../utils/create-segments'; -import { mergeTracks } from '../utils/merge-tracks'; -import { ScoringRuleNames } from '../scoring-rules'; - -/** - * Functions to generate test fixtures for the optimizer tests - */ - -/** - * Test fixture for the optimizer tests - * givenRequest: the OptimizationRequest to test the optimizer - * expectedResult: the expected OptimizationResult that should be returned by the optimizer - */ -export type OptimizerFixture = { - request: OptimizationRequest; - rules: ScoringRuleNames; - expectedResult: Omit; -}; - -/** - * returns an empty track and its expected score - */ -export function createEmptyTrackFixture(): OptimizerFixture { - return { - request: { - track: { points: [], startTimeSec: 0 }, - }, - rules: 'FederationFrancaiseVolLibre', - expectedResult: { - score: 0, - lengthKm: 0, - multiplier: 0, - circuit: undefined, - optimal: true, - }, - }; -} - -export type LatLon = { - lat: number; - lon: number; -}; - -const START_TIME_SEC = Math.round(new Date().getTime() / 1000); - -/** - * @param from LatLon of the starting point - * @param to LatLon of the ending point - * @param nbSegments number of segments to create between the two points - * @param givenRules the ScoringRules for computing the score - * @returns a fixture for a free distance track and it's expected score - */ -export function createFreeDistanceFixture( - from: LatLon, - to: LatLon, - nbSegments: number, - givenRules: ScoringRuleNames, -): OptimizerFixture { - const multiplier = getFreeDistanceMultiplier(givenRules); - const distance = getPreciseDistance(from, to) / 1000; - return { - request: { - track: createSegments( - { ...from, alt: 0, offsetFromStartSec: 0 }, - { ...to, alt: 0, offsetFromStartSec: 60 }, - START_TIME_SEC, - nbSegments, - ), - }, - rules: givenRules, - expectedResult: { - score: distance * multiplier, - lengthKm: distance, - multiplier, - circuit: CircuitType.OpenDistance, - optimal: true, - }, - }; -} - -/** - * - * @param from LatLon of the starting point - * @param intermediate LatLon of the intermediate turn point - * @param to LatLon of the ending point - * @param nbSegments number of segments to create between each given points - * @param givenRules the ScoringRules for computing the score - * @returns a fixture for a free distance track with one intermediate turn point point and it's expected score - */ -export function createFreeDistance1PointFixture( - from: LatLon, - intermediate: LatLon, - to: LatLon, - nbSegments: number, - givenRules: ScoringRuleNames, -): OptimizerFixture { - const distance = (getPreciseDistance(from, intermediate) + getPreciseDistance(intermediate, to)) / 1000; - const multiplier = getFreeDistanceMultiplier(givenRules); - return { - request: { - track: mergeTracks( - createSegments( - { ...from, alt: 0, offsetFromStartSec: 0 }, - { ...intermediate, alt: 0, offsetFromStartSec: 60 }, - START_TIME_SEC, - nbSegments, - ), - createSegments( - { ...intermediate, alt: 0, offsetFromStartSec: 60 }, - { ...to, alt: 0, offsetFromStartSec: 120 }, - START_TIME_SEC, - nbSegments, - ), - ), - }, - rules: givenRules, - expectedResult: { - score: distance * multiplier, - lengthKm: distance, - multiplier, - circuit: CircuitType.OpenDistance, - optimal: true, - }, - }; -} - -/** - * - * @param from LatLon of the starting point - * @param turnPoint1 LatLon of the first intermediate turn point - * @param turnPoint2 LatLon of the second intermediate turn point - * @param to LatLon of the ending point - * @param nbSegments number of segments to create between each given points - * @param givenRules the ScoringRules for computing the score - * @returns a fixture for a free distance track with two intermediate turn points and it's expected score - */ -export function createFreeDistance2PointsFixture( - from: LatLon, - turnPoint1: LatLon, - turnPoint2: LatLon, - to: LatLon, - nbSegments: number, - givenRules: ScoringRuleNames, -): OptimizerFixture { - const distance = - (getPreciseDistance(from, turnPoint1) + - getPreciseDistance(turnPoint1, turnPoint2) + - getPreciseDistance(turnPoint2, to)) / - 1000; - const multiplier = getFreeDistanceMultiplier(givenRules); - return { - request: { - track: mergeTracks( - createSegments( - { ...from, alt: 0, offsetFromStartSec: 0 }, - { ...turnPoint1, alt: 0, offsetFromStartSec: 60 }, - START_TIME_SEC, - nbSegments, - ), - createSegments( - { ...turnPoint1, alt: 0, offsetFromStartSec: 60 }, - { ...turnPoint2, alt: 0, offsetFromStartSec: 120 }, - START_TIME_SEC, - nbSegments, - ), - createSegments( - { ...turnPoint2, alt: 0, offsetFromStartSec: 120 }, - { ...to, alt: 0, offsetFromStartSec: 180 }, - START_TIME_SEC, - nbSegments, - ), - ), - }, - rules: givenRules, - expectedResult: { - score: distance * multiplier, - lengthKm: distance, - multiplier, - circuit: CircuitType.OpenDistance, - optimal: true, - }, - }; -} - -/** - * - * @param from LatLon of the starting point - * @param turnPoint1 LatLon of the first intermediate turn point - * @param turnPoint2 LatLon of the second intermediate turn point - * @param turnPoint3 LatLon of the third intermediate turn point - * @param to LatLon of the ending point - * @param nbSegments number of segments to create between each given points - * @param givenRules the ScoringRules for computing the score - * @returns a fixture for a free distance track with three intermediate turn points and it's expected score - */ -export function createFreeDistance3PointsFixture( - from: LatLon, - turnPoint1: LatLon, - turnPoint2: LatLon, - turnPoint3: LatLon, - to: LatLon, - nbSegments: number, - givenRules: ScoringRuleNames, -): OptimizerFixture { - const distance = - (getPreciseDistance(from, turnPoint1) + - getPreciseDistance(turnPoint1, turnPoint2) + - getPreciseDistance(turnPoint2, turnPoint3) + - getPreciseDistance(turnPoint3, to)) / - 1000; - const multiplier = getFreeDistanceMultiplier(givenRules); - return { - request: { - track: mergeTracks( - createSegments( - { ...from, alt: 0, offsetFromStartSec: 0 }, - { ...turnPoint1, alt: 0, offsetFromStartSec: 60 }, - START_TIME_SEC, - nbSegments, - ), - createSegments( - { ...turnPoint1, alt: 0, offsetFromStartSec: 60 }, - { ...turnPoint2, alt: 0, offsetFromStartSec: 120 }, - START_TIME_SEC, - nbSegments, - ), - createSegments( - { ...turnPoint2, alt: 0, offsetFromStartSec: 120 }, - { ...turnPoint3, alt: 0, offsetFromStartSec: 180 }, - START_TIME_SEC, - nbSegments, - ), - createSegments( - { ...turnPoint3, alt: 0, offsetFromStartSec: 180 }, - { ...to, alt: 0, offsetFromStartSec: 240 }, - START_TIME_SEC, - nbSegments, - ), - ), - }, - rules: givenRules, - expectedResult: { - score: distance * multiplier, - lengthKm: distance, - multiplier, - circuit: CircuitType.OpenDistance, - optimal: true, - }, - }; -} - -/** - * - * @param start LatLon of the starting point of the flat triangle (first point of the triangle) - * @param turnPoint1 LatLon of the second point of the triangle - * @param turnPoint2 LatLon of the third point of the triangle - * @param nbSegments number of segments to create between each given points - * @param givenRules the ScoringRules for computing the score - * @returns a fixture for a flat triangle track and it's expected score - */ -export function createClosedFlatTriangleFixture( - start: LatLon, - turnPoint1: LatLon, - turnPoint2: LatLon, - nbSegments: number, - givenRules: ScoringRuleNames, -): OptimizerFixture { - if (isFAI(start, turnPoint1, turnPoint2)) { - throw new Error('invalid test data: not a flat triangle'); - } - const multiplier = getFlatTriangleMultiplier(givenRules); - return createTriangleFixture( - start, - turnPoint1, - turnPoint2, - nbSegments, - givenRules, - multiplier, - CircuitType.FlatTriangle, - ); -} - -/** - * - * @param start LatLon of the starting point of the flat triangle (first point of the triangle) - * @param turnPoint1 LatLon of the second point of the triangle - * @param nbSegments number of segments to create between each given points - * @param givenRules the ScoringRules for computing the score - * @returns a fixture for a FAI triangle track and it's expected score - * - * The third point of the triangle is computed so that the triangle is equilateral - */ -export function createClosedFaiTriangleFixture( - start: LatLon, - turnPoint1: LatLon, - nbSegments: number, - givenRules: ScoringRuleNames, -): OptimizerFixture { - const distance1 = getPreciseDistance(start, turnPoint1); - const bearingStartToP1 = getGreatCircleBearing(start, turnPoint1); - // The third point 'p2' is at 'distance1' from 'p1' on a line which makes a 60° angle with the line 'start'->'p1' - const equilateralPoint = computeDestinationPoint(start, distance1, bearingStartToP1 + 60); - const p2 = { lat: equilateralPoint.latitude, lon: equilateralPoint.longitude }; - if (!isFAI(start, turnPoint1, p2)) { - throw new Error('invalid test data: not a FAI triangle'); - } - const multiplier = getFaiTriangleMultiplier(givenRules); - return createTriangleFixture(start, turnPoint1, p2, nbSegments, givenRules, multiplier, CircuitType.FaiTriangle); -} - -/** - * same as closedFaiTriangleFixture with a maximum allowed cycle duration of 1 ms for optimization - */ -export function createClosedFaiTriangleFixtureWithSmallCycle( - start: LatLon, - p1: LatLon, - nbIntervals: number, - givenRules: ScoringRuleNames, -): OptimizerFixture { - const standardFixture = createClosedFaiTriangleFixture(start, p1, nbIntervals, givenRules); - return { - request: { - ...standardFixture.request, - maxCycleDurationMs: 1, - }, - rules: givenRules, - expectedResult: standardFixture.expectedResult, - }; -} - -/** - * same as closedFaiTriangleFixture with a only ten iterations allowed for optimization - */ -export function createClosedFaiTriangleFixtureWithSmallLoop( - start: LatLon, - p1: LatLon, - nbIntervals: number, - givenRules: ScoringRuleNames, -): OptimizerFixture { - const standardFixture = createClosedFaiTriangleFixture(start, p1, nbIntervals, givenRules); - return { - request: { - ...standardFixture.request, - maxNumCycles: 10, - }, - rules: givenRules, - expectedResult: standardFixture.expectedResult, - }; -} - -function getFreeDistanceMultiplier(scoringRules: ScoringRuleNames) { - switch (scoringRules) { - case 'CzechLocal': - case 'CzechEuropean': - case 'FederationFrancaiseVolLibre': - case 'Norway': - case 'UnitedKingdomClub': - case 'UnitedKingdomInternational': - case 'UnitedKingdomNational': - case 'XContest': - case 'XContestPPG': - case 'WorldXC': - return 1; - case 'CzechOutsideEurope': - return 0.8; - case 'Leonardo': - return 1.5; - } -} - -function getFlatTriangleMultiplier(scoringRules: ScoringRuleNames) { - switch (scoringRules) { - case 'CzechEuropean': - case 'CzechOutsideEurope': - case 'FederationFrancaiseVolLibre': - case 'UnitedKingdomInternational': - return 1.2; - case 'Leonardo': - case 'WorldXC': - return 1.75; - case 'XContest': - return 1.4; - case 'Norway': - case 'UnitedKingdomClub': - case 'UnitedKingdomNational': - return 1.7; - case 'CzechLocal': - return 1.8; - case 'XContestPPG': - return 2; - } -} - -function getFaiTriangleMultiplier(scoringRules: ScoringRuleNames) { - switch (scoringRules) { - case 'CzechEuropean': - case 'CzechOutsideEurope': - case 'FederationFrancaiseVolLibre': - return 1.4; - case 'Leonardo': - case 'UnitedKingdomClub': - case 'UnitedKingdomNational': - case 'WorldXC': - return 2; - case 'XContest': - return 1.6; - case 'CzechLocal': - return 2.2; - case 'Norway': - return 2.4; - case 'UnitedKingdomInternational': - return 1.5; - case 'XContestPPG': - return 4; - } -} - -function isFAI(p1: LatLon, p2: LatLon, p3: LatLon) { - const distance1 = getPreciseDistance(p1, p2); - const distance2 = getPreciseDistance(p2, p3); - const distance3 = getPreciseDistance(p3, p1); - const totalDistance = distance1 + distance2 + distance3; - const minDistance = Math.min(distance1, distance2, distance3); - const threshold = totalDistance * 0.28; - return minDistance > threshold; -} - -function createTriangleFixture( - start: LatLon, - p1: LatLon, - p2: { lon: number; lat: number }, - nbSegments: number, - givenRules: ScoringRuleNames, - multiplier: number, - circuit: CircuitType, -): OptimizerFixture { - const distance1 = getPreciseDistance(start, p1); - const distance2 = getPreciseDistance(p1, p2); - const distance3 = getPreciseDistance(p2, start); - const lengthKm = (distance1 + distance2 + distance3) / 1000; - const expectedScore = lengthKm * multiplier; - return { - request: { - track: mergeTracks( - createSegments( - { ...start, alt: 0, offsetFromStartSec: 0 }, - { ...p1, alt: 0, offsetFromStartSec: 60 }, - START_TIME_SEC, - nbSegments, - ), - createSegments( - { ...p1, alt: 0, offsetFromStartSec: 60 }, - { ...p2, alt: 0, offsetFromStartSec: 120 }, - START_TIME_SEC, - nbSegments, - ), - createSegments( - { ...p2, alt: 0, offsetFromStartSec: 120 }, - { ...start, alt: 0, offsetFromStartSec: 180 }, - START_TIME_SEC, - nbSegments, - ), - ), - }, - rules: givenRules, - expectedResult: { - score: expectedScore, - lengthKm, - multiplier, - circuit, - optimal: true, - }, - }; -} diff --git a/libs/optimizer/src/lib/optimizer.spec.ts b/libs/optimizer/src/lib/optimizer.spec.ts index 4b59b037..423a086b 100644 --- a/libs/optimizer/src/lib/optimizer.spec.ts +++ b/libs/optimizer/src/lib/optimizer.spec.ts @@ -1,153 +1,294 @@ -import { OptimizationResult, getOptimizer } from './optimizer'; -import { - createClosedFaiTriangleFixture, - createClosedFaiTriangleFixtureWithSmallCycle, - createClosedFaiTriangleFixtureWithSmallLoop, - createClosedFlatTriangleFixture, - createEmptyTrackFixture, - createFreeDistance1PointFixture, - createFreeDistance2PointsFixture, - createFreeDistance3PointsFixture, - createFreeDistanceFixture, - OptimizerFixture, -} from './fixtures/optimizer.fixtures'; -import { scoringRulesNames } from './scoring-rules'; +import { CircuitType, ScoringRequest, ScoringResult, getOptimizer } from './optimizer'; +import { ScoringRuleName, scoringRuleNames } from './scoring-rules'; +import { computeDestinationPoint, getGreatCircleBearing, getPreciseDistance } from 'geolib'; +import { createSegments } from './utils/create-segments'; +import { mergeTracks } from './utils/merge-tracks'; describe('optimizer', () => { - describe('given an empty request', () => { - const fixture = createEmptyTrackFixture(); - it('should return a 0 score', () => { - expectOptimizationIsAsExpected(fixture); - }); - }); - scoringRulesNames.forEach((rules) => { - describe(`${rules} rules`, () => { - const oneSegmentPerBranch = 1; - const tenSegmentsPerBranch = 10; - [oneSegmentPerBranch, tenSegmentsPerBranch].forEach((nbSegmentsPerBranch) => { - describe(`given a free distance request (${nbSegmentsPerBranch} segments/branch)`, () => { - const fixture = createFreeDistanceFixture( - { lat: 45, lon: 5 }, - { lat: 45, lon: 6 }, - nbSegmentsPerBranch, - rules, - ); - it('should return the expected score', () => { - expectOptimizationIsAsExpected(fixture); + scoringRuleNames.forEach((ruleName) => { + describe(`${ruleName} rules`, () => { + it('Scores an empty request with a score of 0', () => { + const request = { + track: { points: [] }, + }; + const result = optimize(request, ruleName); + expect(result).toMatchObject({ + score: 0, + lengthKm: 0, + multiplier: 0, + optimal: true, + }); + }); + + [1, 10].forEach((segmentsPerBranch) => { + describe(`given a free distanceKm request (${segmentsPerBranch} segments/branch)`, () => { + const start = { lat: 45, lon: 5 }; + const end = { lat: 45, lon: 6 }; + + const request = { + track: createSegments({ ...start, alt: 0, timeSec: 0 }, { ...end, alt: 0, timeSec: 60 }, segmentsPerBranch), + }; + + const multiplier = getFreeDistanceMultiplier(ruleName); + const distanceKm = getPreciseDistance(start, end) / 1000; + expect(optimize(request, ruleName)).toMatchObject({ + score: expect.closeTo(distanceKm * multiplier, 1), + lengthKm: expect.closeTo(distanceKm, 1), + multiplier, + circuit: CircuitType.OpenDistance, + optimal: true, }); }); - describe(`given a free distance with 1 intermediate point request (${nbSegmentsPerBranch} segment/branch)`, () => { - const fixture = createFreeDistance1PointFixture( - { lat: 45, lon: 5 }, - { lat: 45, lon: 6 }, - { lat: 46, lon: 6 }, - nbSegmentsPerBranch, - rules, - ); - it('should return the expected score', () => { - expectOptimizationIsAsExpected(fixture); + describe(`given a free distanceKm with 1 turnpoints request (${segmentsPerBranch} segment/branch)`, () => { + const start = { lat: 45, lon: 5 }; + const tp = { lat: 45, lon: 6 }; + const end = { lat: 46, lon: 6 }; + + const request = { + track: mergeTracks( + createSegments({ ...start, alt: 0, timeSec: 0 }, { ...tp, alt: 0, timeSec: 60 }, segmentsPerBranch), + createSegments({ ...tp, alt: 0, timeSec: 60 }, { ...end, alt: 0, timeSec: 120 }, segmentsPerBranch), + ), + }; + + const distanceKm = (getPreciseDistance(start, tp) + getPreciseDistance(tp, end)) / 1000; + const multiplier = getFreeDistanceMultiplier(ruleName); + expect(optimize(request, ruleName)).toMatchObject({ + score: expect.closeTo(distanceKm * multiplier, 1), + lengthKm: expect.closeTo(distanceKm, 1), + multiplier, + circuit: CircuitType.OpenDistance, + optimal: true, }); }); - describe(`given a free distance with 2 intermediate points request (${nbSegmentsPerBranch} segment/branch)`, () => { - const fixture = createFreeDistance2PointsFixture( - { lat: 45, lon: 5 }, - { lat: 45, lon: 6 }, - { lat: 46, lon: 6 }, - { lat: 46, lon: 5 }, - nbSegmentsPerBranch, - rules, - ); - it('should return the expected score (' + nbSegmentsPerBranch + ' segment/branch)', () => { - expectOptimizationIsAsExpected(fixture); + describe(`given a free distanceKm with 2 turnpoints request (${segmentsPerBranch} segment/branch)`, () => { + const start = { lat: 45, lon: 5 }; + const tp1 = { lat: 45, lon: 6 }; + const tp2 = { lat: 46, lon: 6 }; + const end = { lat: 46, lon: 5 }; + + const request = { + track: mergeTracks( + createSegments({ ...start, alt: 0, timeSec: 0 }, { ...tp1, alt: 0, timeSec: 60 }, segmentsPerBranch), + createSegments({ ...tp1, alt: 0, timeSec: 60 }, { ...tp2, alt: 0, timeSec: 120 }, segmentsPerBranch), + createSegments({ ...tp2, alt: 0, timeSec: 120 }, { ...end, alt: 0, timeSec: 180 }, segmentsPerBranch), + ), + }; + + const distanceKm = + (getPreciseDistance(start, tp1) + getPreciseDistance(tp1, tp2) + getPreciseDistance(tp2, end)) / 1000; + const multiplier = getFreeDistanceMultiplier(ruleName); + expect(optimize(request, ruleName)).toMatchObject({ + score: expect.closeTo(distanceKm * multiplier, 1), + lengthKm: expect.closeTo(distanceKm, 1), + multiplier, + circuit: CircuitType.OpenDistance, + optimal: true, }); }); - describe(`given a free distance with 3 intermediate points request (${nbSegmentsPerBranch} segment/branch)`, () => { - const fixture = createFreeDistance3PointsFixture( - { lat: 45, lon: 5 }, - { lat: 45, lon: 6 }, - { lat: 46, lon: 6 }, - { lat: 46, lon: 5 }, - { lat: 47, lon: 5 }, - nbSegmentsPerBranch, - rules, - ); - it('should return the expected score', () => { - expectOptimizationIsAsExpected(fixture); + describe(`given a free distanceKm with 3 turnpoints request (${segmentsPerBranch} segment/branch)`, () => { + const start = { lat: 45, lon: 5 }; + const tp1 = { lat: 45, lon: 6 }; + const tp2 = { lat: 46, lon: 6 }; + const tp3 = { lat: 46, lon: 5 }; + const end = { lat: 47, lon: 5 }; + + const request = { + track: mergeTracks( + createSegments({ ...start, alt: 0, timeSec: 0 }, { ...tp1, alt: 0, timeSec: 60 }, segmentsPerBranch), + createSegments({ ...tp1, alt: 0, timeSec: 60 }, { ...tp2, alt: 0, timeSec: 120 }, segmentsPerBranch), + createSegments({ ...tp2, alt: 0, timeSec: 120 }, { ...tp3, alt: 0, timeSec: 180 }, segmentsPerBranch), + createSegments({ ...tp3, alt: 0, timeSec: 180 }, { ...end, alt: 0, timeSec: 240 }, segmentsPerBranch), + ), + }; + + const distanceKm = + (getPreciseDistance(start, tp1) + + getPreciseDistance(tp1, tp2) + + getPreciseDistance(tp2, tp3) + + getPreciseDistance(tp3, end)) / + 1000; + const multiplier = getFreeDistanceMultiplier(ruleName); + expect(optimize(request, ruleName)).toMatchObject({ + score: expect.closeTo(distanceKm * multiplier, 1), + lengthKm: expect.closeTo(distanceKm, 1), + multiplier, + circuit: CircuitType.OpenDistance, + optimal: true, }); }); - describe(`given a closed flat triangle request (${nbSegmentsPerBranch} segment/branch)`, () => { - const fixture = createClosedFlatTriangleFixture( - { lat: 45, lon: 5 }, - { lat: 45, lon: 6 }, - { lat: 45.2, lon: 6 }, - nbSegmentsPerBranch, - rules, - ); - it('should return the expected score', () => { - expectOptimizationIsAsExpected(fixture); + describe(`given a closed flat triangle request (${segmentsPerBranch} segment/branch)`, () => { + const tp1 = { lat: 45, lon: 5 }; + const tp2 = { lat: 45, lon: 6 }; + const tp3 = { lat: 45.2, lon: 6 }; + + const request = { + track: mergeTracks( + createSegments({ ...tp1, alt: 0, timeSec: 0 }, { ...tp2, alt: 0, timeSec: 60 }, segmentsPerBranch), + createSegments({ ...tp2, alt: 0, timeSec: 60 }, { ...tp3, alt: 0, timeSec: 120 }, segmentsPerBranch), + createSegments({ ...tp3, alt: 0, timeSec: 120 }, { ...tp1, alt: 0, timeSec: 180 }, segmentsPerBranch), + ), + }; + + const distanceKm = + (getPreciseDistance(tp1, tp2) + getPreciseDistance(tp2, tp3) + getPreciseDistance(tp3, tp1)) / 1000; + const multiplier = getFlatTriangleMultiplier(ruleName); + expect(optimize(request, ruleName)).toMatchObject({ + score: expect.closeTo(distanceKm * multiplier, 1), + lengthKm: expect.closeTo(distanceKm, 1), + multiplier, + circuit: CircuitType.FlatTriangle, + optimal: true, }); }); - describe(`given a closed FAI triangle request (${nbSegmentsPerBranch} segment/branch)`, () => { - const fixture = createClosedFaiTriangleFixture( - { lat: 45, lon: 5 }, - { lat: 45, lon: 6 }, - nbSegmentsPerBranch, - rules, - ); - it('should return the expected score', () => { - expectOptimizationIsAsExpected(fixture); + describe(`given a closed FAI triangle request (${segmentsPerBranch} segment/branch)`, () => { + const tp1 = { lat: 45, lon: 5 }; + const tp2 = { lat: 45, lon: 6 }; + + const distance1 = getPreciseDistance(tp1, tp2); + const bearing = getGreatCircleBearing(tp1, tp2); + // Build an equilateral triangle + const tp3GeoLib = computeDestinationPoint(tp1, distance1, bearing + 60); + const tp3 = { lat: tp3GeoLib.latitude, lon: tp3GeoLib.longitude }; + + const request = { + track: mergeTracks( + createSegments({ ...tp1, alt: 0, timeSec: 0 }, { ...tp2, alt: 0, timeSec: 60 }, segmentsPerBranch), + createSegments({ ...tp2, alt: 0, timeSec: 60 }, { ...tp3, alt: 0, timeSec: 120 }, segmentsPerBranch), + createSegments({ ...tp3, alt: 0, timeSec: 120 }, { ...tp1, alt: 0, timeSec: 180 }, segmentsPerBranch), + ), + }; + + const distanceKm = + (getPreciseDistance(tp1, tp2) + getPreciseDistance(tp2, tp3) + getPreciseDistance(tp3, tp1)) / 1000; + const multiplier = getFaiTriangleMultiplier(ruleName); + expect(optimize(request, ruleName)).toMatchObject({ + score: expect.closeTo(distanceKm * multiplier, 1), + lengthKm: expect.closeTo(distanceKm, 1), + multiplier, + circuit: CircuitType.FaiTriangle, + optimal: true, }); }); }); }); }); - describe('given a closed FAI triangle request (10 segments/branch) with minimal cycle allowed', () => { - const fixture = createClosedFaiTriangleFixtureWithSmallCycle( - { lat: 45, lon: 5 }, - { lat: 45, lon: 6 }, - 9, - 'FederationFrancaiseVolLibre', - ); - it('should return the expected score', () => { - expectOptimizationIsAsExpected(fixture); - }); - }); + it('given a closed FAI triangle request (10 segments/branch) with minimal loop allowed', () => { + const tp1 = { lat: 45, lon: 5 }; + const tp2 = { lat: 45, lon: 6 }; - describe('given a closed FAI triangle request (10 segments/branch) with minimal loop allowed', () => { - const fixture = createClosedFaiTriangleFixtureWithSmallLoop( - { lat: 45, lon: 5 }, - { lat: 45, lon: 6 }, - 9, - 'FederationFrancaiseVolLibre', - ); - it('should return the expected score', () => { - expectOptimizationIsAsExpected(fixture); + const distance1 = getPreciseDistance(tp1, tp2); + const bearing = getGreatCircleBearing(tp1, tp2); + // Build an equilateral triangle + const tp3GeoLib = computeDestinationPoint(tp1, distance1, bearing + 60); + const tp3 = { lat: tp3GeoLib.latitude, lon: tp3GeoLib.longitude }; + + const request: ScoringRequest = { + track: mergeTracks( + createSegments({ ...tp1, alt: 0, timeSec: 0 }, { ...tp2, alt: 0, timeSec: 60 }, 10), + createSegments({ ...tp2, alt: 0, timeSec: 60 }, { ...tp3, alt: 0, timeSec: 120 }, 10), + createSegments({ ...tp3, alt: 0, timeSec: 120 }, { ...tp1, alt: 0, timeSec: 180 }, 10), + ), + maxNumCycles: 1, + }; + + const distanceKm = + (getPreciseDistance(tp1, tp2) + getPreciseDistance(tp2, tp3) + getPreciseDistance(tp3, tp1)) / 1000; + const multiplier = getFaiTriangleMultiplier('FFVL'); + expect(optimize(request, 'FFVL')).toMatchObject({ + score: expect.closeTo(distanceKm * multiplier, 1), + lengthKm: expect.closeTo(distanceKm, 1), + multiplier, + circuit: CircuitType.FaiTriangle, + optimal: true, }); }); +}); - // TODO: IsAsExpected does not really describe the behavior. Something with expect(optimize(...)).toHaveScore(...); - // should be better - function expectOptimizationIsAsExpected(fixture: OptimizerFixture) { - const optimization = getOptimizer(fixture.request, fixture.rules); - let currentResult: IteratorResult, - done = false; - while (!done) { - currentResult = optimization.next(); - done = currentResult.done; - } - expect(currentResult.value.score).toBeCloseTo(fixture.expectedResult.score, 1); - expect(currentResult.value.lengthKm).toBeCloseTo(fixture.expectedResult.lengthKm, 1); - expect(currentResult.value.multiplier).toEqual(fixture.expectedResult.multiplier); - expect(currentResult.value.circuit).toEqual(fixture.expectedResult.circuit); - currentResult.value.solutionIndices.forEach((index) => { - expect(index).toBeGreaterThanOrEqual(0); - expect(index).toBeLessThan(fixture.request.track.points.length); - }); +function optimize(request: ScoringRequest, ruleName: ScoringRuleName): ScoringResult { + const optimizer = getOptimizer(request, ruleName); + let result: IteratorResult; + do { + result = optimizer.next(); + } while (!result.done); + + expect(result.value.optimal).toBe(true); + + return result.value; +} + +// TODO: refactor to extract from the rules +function getFreeDistanceMultiplier(scoringRules: ScoringRuleName) { + switch (scoringRules) { + case 'CzechLocal': + case 'CzechEurope': + case 'FFVL': + case 'Norway': + case 'UKClub': + case 'UKInternational': + case 'UKNational': + case 'XContest': + case 'XContestPPG': + case 'WorldXC': + return 1; + case 'CzechOutsideEurope': + return 0.8; + case 'Leonardo': + return 1.5; } -}); +} + +// TODO: refactor to extract from the rules +function getFlatTriangleMultiplier(scoringRules: ScoringRuleName) { + switch (scoringRules) { + case 'CzechEurope': + case 'CzechOutsideEurope': + case 'FFVL': + case 'UKInternational': + return 1.2; + case 'Leonardo': + case 'WorldXC': + return 1.75; + case 'XContest': + return 1.4; + case 'Norway': + case 'UKClub': + case 'UKNational': + return 1.7; + case 'CzechLocal': + return 1.8; + case 'XContestPPG': + return 2; + } +} + +// TODO: refactor to extract from the rules +function getFaiTriangleMultiplier(scoringRules: ScoringRuleName) { + switch (scoringRules) { + case 'CzechEurope': + case 'CzechOutsideEurope': + case 'FFVL': + return 1.4; + case 'Leonardo': + case 'UKClub': + case 'UKNational': + case 'WorldXC': + return 2; + case 'XContest': + return 1.6; + case 'CzechLocal': + return 2.2; + case 'Norway': + return 2.4; + case 'UKInternational': + return 1.5; + case 'XContestPPG': + return 4; + } +} diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index 33ad5c92..2bffe644 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -2,7 +2,7 @@ import { solver, Solution } from 'igc-xc-score'; import { BRecord, IGCFile } from 'igc-parser'; -import { ScoringRuleNames, scoringRules } from './scoring-rules'; +import { ScoringRuleName, scoringRules } from './scoring-rules'; // Minimum number of points in an igc-xc-score track. // See this issue https://github.com/mmomtchev/igc-xc-score/issues/231 @@ -12,22 +12,14 @@ export interface LatLonAltTime { alt: number; lat: number; lon: number; - /** - * TODO: make this an absolute time, remove the start time - * Time relative to the start of the track. - */ - offsetFromStartSec: number; + timeSec: number; } export interface ScoringTrack { points: LatLonAltTime[]; - /** - * Timestamp of the start of the track. - */ - startTimeSec: number; } -export interface OptimizationRequest { +export interface ScoringRequest { track: ScoringTrack; /** * Maximum duration for an optimization round trip. @@ -48,7 +40,7 @@ export enum CircuitType { OutAndReturn = 'Out and return', } -export interface OptimizationResult { +export interface ScoringResult { /** * The score for the track in the given league */ @@ -89,13 +81,13 @@ export interface OptimizationResult { * @see README.md * * @param request Contains the tracks and options. - * @param rules The ScoringRules to use. + * @param ruleName The ScoringRules to use. * @return an Iterator of OptimizationResult */ export function* getOptimizer( - request: OptimizationRequest, - rules: ScoringRuleNames, -): Iterator { + request: ScoringRequest, + ruleName: ScoringRuleName, +): Iterator { if (request.track.points.length == 0) { // console.warn('Empty track received in optimization request. Returns a 0 score'); return { @@ -109,7 +101,7 @@ export function* getOptimizer( const originalTrack = request.track; const solverTrack = appendPointsIfNeeded(originalTrack, MIN_IGC_XC_SCORE_POINTS); const flight = toIgcFile(solverTrack); - const solverScoringRules = scoringRules.get(rules); + const solverScoringRules = scoringRules.get(ruleName); const options = toSolverOptions(request); const solutionIterator = solver(flight, solverScoringRules || {}, options); while (true) { @@ -140,7 +132,7 @@ function appendPointsIfNeeded(track: ScoringTrack, minValidLength: number) { track.points.push({ ...lastPoint, lat: lastPoint.lat + 0.000001, - offsetFromStartSec: lastPoint.offsetFromStartSec + 60, + timeSec: lastPoint.timeSec + 60, }); } // console.debug(`new track has ${newTrack.points.length} points`); @@ -152,11 +144,15 @@ function appendPointsIfNeeded(track: ScoringTrack, minValidLength: number) { * @param track the source track */ function toIgcFile(track: ScoringTrack): IGCFile { + if (track.points.length == 0) { + throw new Error('Empty track'); + } + const fixes = track.points.map((point): BRecord => { - const timeMilliseconds = point.offsetFromStartSec * 1000; + const timeMilliSec = point.timeSec * 1000; return { - timestamp: timeMilliseconds, - time: new Date(timeMilliseconds).toISOString(), + timestamp: timeMilliSec, + time: new Date(timeMilliSec).toISOString(), latitude: point.lat, longitude: point.lon, valid: true, @@ -170,12 +166,12 @@ function toIgcFile(track: ScoringTrack): IGCFile { // Only fill out the fields required by igc-xc-score. return { - date: new Date(track.startTimeSec * 1000).toISOString(), + date: new Date(track.points[0].timeSec * 1000).toISOString(), fixes: fixes, } as any; } -function toSolverOptions(request: OptimizationRequest) { +function toSolverOptions(request: ScoringRequest) { // TODO: upstream the type to igc-xc-score return { maxcycle: request.maxCycleDurationMs, @@ -183,7 +179,7 @@ function toSolverOptions(request: OptimizationRequest) { }; } -function toOptimizationResult(solution: Solution, originalTrack: ScoringTrack): OptimizationResult { +function toOptimizationResult(solution: Solution, originalTrack: ScoringTrack): ScoringResult { return { score: solution.score ?? 0, lengthKm: solution.scoreInfo?.distance ?? 0, diff --git a/libs/optimizer/src/lib/scoring-rules.ts b/libs/optimizer/src/lib/scoring-rules.ts index 6171a56a..8cc5932e 100644 --- a/libs/optimizer/src/lib/scoring-rules.ts +++ b/libs/optimizer/src/lib/scoring-rules.ts @@ -1,114 +1,113 @@ import * as igcXcScore from 'igc-xc-score'; -// TODO: this should be `keyof typeof igcXcScore.scoringRules` if the types were correct -export const scoringRulesNames = [ +export const scoringRuleNames = [ 'CzechLocal', - 'CzechEuropean', + 'CzechEurope', 'CzechOutsideEurope', - 'FederationFrancaiseVolLibre', + 'FFVL', 'Leonardo', 'Norway', - 'UnitedKingdomClub', - 'UnitedKingdomInternational', - 'UnitedKingdomNational', + 'UKClub', + 'UKInternational', + 'UKNational', 'XContest', 'XContestPPG', 'WorldXC', ] as const; -export type ScoringRuleNames = (typeof scoringRulesNames)[number]; +export type ScoringRuleName = (typeof scoringRuleNames)[number]; // TODO: Export the rules from igc-xc-score const scoringBaseModel = igcXcScore.scoringRules['XContest']; -const openDistanceBase = scoringBaseModel[0]; -const freeTriangleBase = scoringBaseModel[1]; -const faiTriangleBase = scoringBaseModel[2]; -const outAndReturnBase = igcXcScore.scoringRules['FAI-OAR'][0]; +const openDistance = scoringBaseModel[0]; +const freeTriangle = scoringBaseModel[1]; +const faiTriangle = scoringBaseModel[2]; +const outAndReturn = igcXcScore.scoringRules['FAI-OAR'][0]; const czechLocalRule = [ - { ...openDistanceBase, multiplier: 1 }, - { ...freeTriangleBase, multiplier: 1.8 }, - { ...faiTriangleBase, multiplier: 2.2 }, + { ...openDistance, multiplier: 1 }, + { ...freeTriangle, multiplier: 1.8 }, + { ...faiTriangle, multiplier: 2.2 }, ]; const czechEuropeRule = [ - { ...openDistanceBase, multiplier: 1 }, - { ...freeTriangleBase, multiplier: 1.2 }, - { ...faiTriangleBase, multiplier: 1.4 }, + { ...openDistance, multiplier: 1 }, + { ...freeTriangle, multiplier: 1.2 }, + { ...faiTriangle, multiplier: 1.4 }, ]; const czechOutEuropeRule = [ - { ...openDistanceBase, multiplier: 0.8 }, - { ...freeTriangleBase, multiplier: 1.2 }, - { ...faiTriangleBase, multiplier: 1.4 }, + { ...openDistance, multiplier: 0.8 }, + { ...freeTriangle, multiplier: 1.2 }, + { ...faiTriangle, multiplier: 1.4 }, ]; const leonardoRule = [ - { ...openDistanceBase, multiplier: 1.5 }, - { ...freeTriangleBase, multiplier: 1.75, closingDistanceRelative: 0.2 }, - { ...faiTriangleBase, multiplier: 2, closingDistanceRelative: 0.2 }, + { ...openDistance, multiplier: 1.5 }, + { ...freeTriangle, multiplier: 1.75, closingDistanceRelative: 0.2 }, + { ...faiTriangle, multiplier: 2, closingDistanceRelative: 0.2 }, ]; const norwayRule = [ - { ...openDistanceBase, multiplier: 1 }, - { ...freeTriangleBase, multiplier: 1.7, closingDistanceRelative: 0.05 }, - { ...freeTriangleBase, multiplier: 1.5, closingDistanceRelative: 0.2 }, - { ...faiTriangleBase, multiplier: 2.4, closingDistanceRelative: 0.05 }, - { ...faiTriangleBase, multiplier: 2.2, closingDistanceRelative: 0.2 }, + { ...openDistance, multiplier: 1 }, + { ...freeTriangle, multiplier: 1.7, closingDistanceRelative: 0.05 }, + { ...freeTriangle, multiplier: 1.5, closingDistanceRelative: 0.2 }, + { ...faiTriangle, multiplier: 2.4, closingDistanceRelative: 0.05 }, + { ...faiTriangle, multiplier: 2.2, closingDistanceRelative: 0.2 }, ]; const ukXclClubRule = [ - { ...openDistanceBase, multiplier: 1, minDistance: 5 }, - { ...outAndReturnBase, multiplier: 1.2, minDistance: 5 }, - { ...outAndReturnBase, multiplier: 1.3, minDistance: 15 }, - { ...outAndReturnBase, multiplier: 1.7, minDistance: 35 }, - { ...freeTriangleBase, multiplier: 1.2, minDistance: 5 }, - { ...freeTriangleBase, multiplier: 1.3, minDistance: 15 }, - { ...freeTriangleBase, multiplier: 1.7, minDistance: 35 }, - { ...faiTriangleBase, multiplier: 1.5, minDistance: 5 }, - { ...faiTriangleBase, multiplier: 1.7, minDistance: 15 }, - { ...faiTriangleBase, multiplier: 2, minDistance: 35 }, + { ...openDistance, multiplier: 1, minDistance: 5 }, + { ...outAndReturn, multiplier: 1.2, minDistance: 5 }, + { ...outAndReturn, multiplier: 1.3, minDistance: 15 }, + { ...outAndReturn, multiplier: 1.7, minDistance: 35 }, + { ...freeTriangle, multiplier: 1.2, minDistance: 5 }, + { ...freeTriangle, multiplier: 1.3, minDistance: 15 }, + { ...freeTriangle, multiplier: 1.7, minDistance: 35 }, + { ...faiTriangle, multiplier: 1.5, minDistance: 5 }, + { ...faiTriangle, multiplier: 1.7, minDistance: 15 }, + { ...faiTriangle, multiplier: 2, minDistance: 35 }, ]; const ukXclInternationalRule = [ - { ...openDistanceBase, multiplier: 1, minDistance: 10 }, - { ...outAndReturnBase, multiplier: 1.2, minDistance: 35 }, - { ...freeTriangleBase, multiplier: 1.2, minDistance: 35 }, - { ...faiTriangleBase, multiplier: 1.5, minDistance: 25 }, + { ...openDistance, multiplier: 1, minDistance: 10 }, + { ...outAndReturn, multiplier: 1.2, minDistance: 35 }, + { ...freeTriangle, multiplier: 1.2, minDistance: 35 }, + { ...faiTriangle, multiplier: 1.5, minDistance: 25 }, ]; const ukXclNationalRule = [ - { ...openDistanceBase, multiplier: 1, minDistance: 10 }, - { ...outAndReturnBase, multiplier: 1.3, minDistance: 15 }, - { ...outAndReturnBase, multiplier: 1.7, minDistance: 35 }, - { ...freeTriangleBase, multiplier: 1.3, minDistance: 15 }, - { ...freeTriangleBase, multiplier: 1.7, minDistance: 35 }, - { ...faiTriangleBase, multiplier: 1.7, minDistance: 15 }, - { ...faiTriangleBase, multiplier: 2, minDistance: 25 }, + { ...openDistance, multiplier: 1, minDistance: 10 }, + { ...outAndReturn, multiplier: 1.3, minDistance: 15 }, + { ...outAndReturn, multiplier: 1.7, minDistance: 35 }, + { ...freeTriangle, multiplier: 1.3, minDistance: 15 }, + { ...freeTriangle, multiplier: 1.7, minDistance: 35 }, + { ...faiTriangle, multiplier: 1.7, minDistance: 15 }, + { ...faiTriangle, multiplier: 2, minDistance: 25 }, ]; const xContestPpgRule = [ - { ...openDistanceBase, multiplier: 1 }, - { ...freeTriangleBase, multiplier: 2, closingDistanceFixed: 0.8 }, - { ...faiTriangleBase, multiplier: 4, closingDistanceFixed: 0.8 }, + { ...openDistance, multiplier: 1 }, + { ...freeTriangle, multiplier: 2, closingDistanceFixed: 0.8 }, + { ...faiTriangle, multiplier: 4, closingDistanceFixed: 0.8 }, ]; const wxcRule = [ - { ...openDistanceBase, multiplier: 1 }, - { ...freeTriangleBase, multiplier: 1.75, closingDistanceRelative: 0.2 }, - { ...faiTriangleBase, multiplier: 2, closingDistanceFixed: 0.2 }, + { ...openDistance, multiplier: 1 }, + { ...freeTriangle, multiplier: 1.75, closingDistanceRelative: 0.2 }, + { ...faiTriangle, multiplier: 2, closingDistanceFixed: 0.2 }, ]; -export const scoringRules: Map = new Map([ - ['CzechEuropean', czechEuropeRule], +export const scoringRules: Map = new Map([ + ['CzechEurope', czechEuropeRule], ['CzechLocal', czechLocalRule], ['CzechOutsideEurope', czechOutEuropeRule], - ['FederationFrancaiseVolLibre', igcXcScore.scoringRules['FFVL']], + ['FFVL', igcXcScore.scoringRules['FFVL']], ['Leonardo', leonardoRule], ['Norway', norwayRule], - ['UnitedKingdomClub', ukXclClubRule], - ['UnitedKingdomInternational', ukXclInternationalRule], - ['UnitedKingdomNational', ukXclNationalRule], + ['UKClub', ukXclClubRule], + ['UKInternational', ukXclInternationalRule], + ['UKNational', ukXclNationalRule], ['XContest', igcXcScore.scoringRules['XContest']], ['XContestPPG', xContestPpgRule], ['WorldXC', wxcRule], diff --git a/libs/optimizer/src/lib/utils/create-segments.ts b/libs/optimizer/src/lib/utils/create-segments.ts index 66296a6e..43aa6af2 100644 --- a/libs/optimizer/src/lib/utils/create-segments.ts +++ b/libs/optimizer/src/lib/utils/create-segments.ts @@ -1,46 +1,31 @@ import { LatLonAltTime, ScoringTrack } from '../optimizer'; /** - * Create segments between 2 points. - * Added points are computed by a linear interpolation - * @param from start point of the segment - * @param to end point - * @param minTimeSec time in seconds since 1970-01-01T00:00:00.000 when the track starts - * @param nbSegments number of segments created. If nbSegments <= 1 the result contains one segment ('from' -> 'to') - * @param distributionFactor if nbSegments > 1, this factor will narrow the distance between generated points and the start - * point of the segment. if close to zero, points will be close to the start point. - * if equals 1, points will be equally distributed along the segment. + * Creates a track with segments. + * + * Points are computed by a linear interpolation + * * @return a ScoringTrack of nbSegments */ -export function createSegments( - from: LatLonAltTime, - to: LatLonAltTime, - minTimeSec: number, - nbSegments: number, - distributionFactor = 1, -): ScoringTrack { - const result: ScoringTrack = { points: [], startTimeSec: minTimeSec }; +export function createSegments(startPoint: LatLonAltTime, endPoint: LatLonAltTime, nbSegments: number): ScoringTrack { + const points: LatLonAltTime[] = []; - result.points.push(from); + points.push(startPoint); - if (nbSegments > 1) { - appendIntermediatePoints(); + const deltaLat = (endPoint.lat - startPoint.lat) / nbSegments; + const deltaLon = (endPoint.lon - startPoint.lon) / nbSegments; + const deltaAlt = (endPoint.alt - startPoint.alt) / nbSegments; + const deltaTimeSec = (endPoint.timeSec - startPoint.timeSec) / nbSegments; + for (let index = 1; index < nbSegments; index++) { + points.push({ + lat: startPoint.lat + deltaLat * index, + lon: startPoint.lon + deltaLon * index, + alt: Math.round(startPoint.alt + deltaAlt * index), + timeSec: Math.round(startPoint.timeSec + deltaTimeSec * index), + }); } - result.points.push(to); - return result; - function appendIntermediatePoints() { - const deltaLat = ((to.lat - from.lat) * distributionFactor) / nbSegments; - const deltaLon = ((to.lon - from.lon) * distributionFactor) / nbSegments; - const deltaAlt = ((to.alt - from.alt) * distributionFactor) / nbSegments; - const deltaTimeSec = ((to.offsetFromStartSec - from.offsetFromStartSec) * distributionFactor) / nbSegments; - for (let index = 1; index < nbSegments; index++) { - result.points.push({ - lat: from.lat + deltaLat * index, - lon: from.lon + deltaLon * index, - alt: Math.round(from.alt + deltaAlt * index), - offsetFromStartSec: from.offsetFromStartSec + deltaTimeSec * index, - }); - } - } + points.push(endPoint); + + return { points }; } diff --git a/libs/optimizer/src/lib/utils/merge-tracks.ts b/libs/optimizer/src/lib/utils/merge-tracks.ts index 077d31bb..79d0c33e 100644 --- a/libs/optimizer/src/lib/utils/merge-tracks.ts +++ b/libs/optimizer/src/lib/utils/merge-tracks.ts @@ -18,8 +18,5 @@ export function mergeTracks(...tracks: ScoringTrack[]): ScoringTrack { const collapse = points.at(-1)?.lat === track.points[0].lat && points.at(-1)?.lon === track.points[0].lon; points.push(...(collapse ? track.points.slice(1) : track.points)); } - return { - points, - startTimeSec: 0, - }; + return { points }; } From 0d737bd7b497b06072b58a878f4246c43c850b18 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Sat, 1 Jun 2024 09:11:28 +0200 Subject: [PATCH 08/20] minor tweaks --- .../src/app/components/ui/about-modal.ts | 3 +- package-lock.json | 562 +++++++++--------- package.json | 36 +- 3 files changed, 301 insertions(+), 300 deletions(-) diff --git a/apps/fxc-front/src/app/components/ui/about-modal.ts b/apps/fxc-front/src/app/components/ui/about-modal.ts index 0ffceabd..11584fa9 100644 --- a/apps/fxc-front/src/app/components/ui/about-modal.ts +++ b/apps/fxc-front/src/app/components/ui/about-modal.ts @@ -20,7 +20,8 @@ export class AboutModal extends LitElement { Momtchil Momtchev, Stanislav Ošmera, Tristan Horn, - Sylvain Pasutto + Sylvain Pasutto, + flyingtof

diff --git a/package-lock.json b/package-lock.json index 2a5fca75..bf524ad1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@dr.pogodin/csurf": "^1.13.0", "@google-cloud/compute": "^4.7.0", "@google-cloud/datastore": "^9.0.0", - "@google-cloud/pubsub": "^4.4.0", + "@google-cloud/pubsub": "^4.4.1", "@google-cloud/storage": "^7.11.1", "@googlemaps/js-api-loader": "^1.16.6", "@ionic/core": "^8.2.0", @@ -22,7 +22,7 @@ "@popperjs/core": "^2.11.8", "@protobuf-ts/runtime": "^2.9.4", "@reduxjs/toolkit": "^2.2.5", - "@stencil/core": "^4.18.2", + "@stencil/core": "^4.18.3", "@swc-node/register": "1.8.0", "@swc/core": "^1.3.95", "@tmcw/togeojson": "^5.8.1", @@ -42,7 +42,7 @@ "express-session": "^1.18.0", "geojson": "^0.5.0", "geolib": "^3.3.4", - "glob": "^10.3.15", + "glob": "^10.4.1", "google-polyline": "^1.0.3", "gpx-builder": "^5.3.0", "grant": "^5.4.22", @@ -74,17 +74,17 @@ "@esri/arcgis-rest-geocoding": "^4.0.2", "@esri/arcgis-rest-request": "^4.2.1", "@nx-tools/nx-container": "^6.0.1", - "@nx/cypress": "19.1.0", - "@nx/eslint": "19.1.0", - "@nx/eslint-plugin": "19.1.0", - "@nx/express": "19.1.0", - "@nx/jest": "19.1.0", - "@nx/js": "19.1.0", - "@nx/node": "19.1.0", - "@nx/vite": "19.1.0", - "@nx/web": "19.1.0", - "@nx/webpack": "19.1.0", - "@nx/workspace": "19.1.0", + "@nx/cypress": "19.1.1", + "@nx/eslint": "19.1.1", + "@nx/eslint-plugin": "19.1.1", + "@nx/express": "19.1.1", + "@nx/jest": "19.1.1", + "@nx/js": "19.1.1", + "@nx/node": "19.1.1", + "@nx/vite": "19.1.1", + "@nx/web": "19.1.1", + "@nx/webpack": "19.1.1", + "@nx/workspace": "19.1.1", "@protobuf-ts/plugin": "^2.9.4", "@swc/helpers": "~0.5.2", "@types/compression": "^1.7.5", @@ -94,7 +94,7 @@ "@types/express-fileupload": "^1.5.0", "@types/express-session": "^1.18.0", "@types/google.maps": "^3.55.9", - "@types/gtag.js": "^0.0.19", + "@types/gtag.js": "^0.0.20", "@types/ioredis": "^4.28.10", "@types/jest": "29.4.0", "@types/js-yaml": "^4.0.5", @@ -119,12 +119,12 @@ "jest-environment-node": "^29.4.1", "jsdom": "~22.1.0", "mailersend": "^2.2.0", - "nx": "19.1.0", + "nx": "19.1.1", "prettier": "^2.6.2", "rollup-plugin-minify-html-literals": "^1.2.6", "rollup-plugin-visualizer": "^5.12.0", - "servez": "^2.1.4", - "ts-jest": "^29.1.0", + "servez": "^2.1.6", + "ts-jest": "^29.1.4", "ts-node": "^10.9.2", "typescript": "5.4.5", "vite": "~5.0.0", @@ -2914,12 +2914,12 @@ "integrity": "sha512-wHQYWFtDa6c328EraXEVZvgOiaQyYr0yuaaZ0G3cB4C3lSkWefW34L/e5TLAhtuG3zJ/wR6pl5X1YYNfBc0/4Q==" }, "node_modules/@esri/calcite-components": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@esri/calcite-components/-/calcite-components-2.8.3.tgz", - "integrity": "sha512-QjDHHGzHP/idZITb1KKjbSAmISuDPaR8M2MsIjRKdVjGpLAIhCyHtlCSHOux46E4kKYgEMrui5ExQ3wwZpW3Ew==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@esri/calcite-components/-/calcite-components-2.9.0.tgz", + "integrity": "sha512-caFnI1lTtpHzm4SRx6VHETRKIoe3UeytV7m6DrwTMnwAosIgfv86ttJ2rhxgXXcnqptCesJSf2TxUiOqc/vc+g==", "dependencies": { - "@floating-ui/dom": "1.6.3", - "@stencil/core": "4.17.1", + "@floating-ui/dom": "1.6.5", + "@stencil/core": "4.18.2", "@types/color": "3.0.6", "color": "4.2.3", "composed-offset-position": "0.0.4", @@ -2932,9 +2932,9 @@ } }, "node_modules/@esri/calcite-components/node_modules/@stencil/core": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.17.1.tgz", - "integrity": "sha512-nlARe1QtK5abnCG8kPQKJMWiELg39vKabvf3ebm6YEhQA35CgrxC1pVYTsYq3yktJKoY+k+VzGRnATLKyaLbvA==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.18.2.tgz", + "integrity": "sha512-GLYbzv3Bq/oUbQk3CH09zkjISANccyE5/A1C7+1JZhdnWUx1MRuWQR9/2uzSPR7kF0sdppwzXvArl7VqYCxLOQ==", "bin": { "stencil": "bin/stencil" }, @@ -2966,9 +2966,9 @@ } }, "node_modules/@floating-ui/dom": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", - "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz", + "integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==", "dependencies": { "@floating-ui/core": "^1.0.0", "@floating-ui/utils": "^0.2.0" @@ -3046,9 +3046,9 @@ } }, "node_modules/@google-cloud/pubsub": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-4.4.0.tgz", - "integrity": "sha512-1eiiAZUFhxcOqKPVwZarc3ghXuhoc3S7z5BgNrxqdirJ/MYr3IjQVTA7Lq2dAAsDuWms1LBN897rbnEGW9PpfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-4.4.1.tgz", + "integrity": "sha512-OsNsadtM+/EhHijc8pIgf+GaqWIZIaizhq6p2mzK+lB7BRziV66ByMDO6EEtyqcdmqYh6MbQ39RZMEQocZsxPQ==", "dependencies": { "@google-cloud/paginator": "^5.0.0", "@google-cloud/precise-date": "^4.0.0", @@ -3059,7 +3059,7 @@ "arrify": "^2.0.0", "extend": "^3.0.2", "google-auth-library": "^9.3.0", - "google-gax": "^4.3.1", + "google-gax": "^4.3.3", "heap-js": "^2.2.0", "is-stream-ended": "^0.1.4", "lodash.snakecase": "^4.1.1", @@ -3757,75 +3757,75 @@ } }, "node_modules/@nrwl/cypress": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/cypress/-/cypress-19.1.0.tgz", - "integrity": "sha512-V+lCej/t1HknAtIT3be48palqvynrHlcNR+ivZWDN7kTw6DQw4aAXbWyEUP7f0Qgn4AaahlYkdBJRssQ0IDBGA==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/cypress/-/cypress-19.1.1.tgz", + "integrity": "sha512-sorUYgADz1MxM7veujJuQ5IohXkbTWu0gPJcZeTUB2TGzpqsqjVTfQ5pHzMRG8LFvL0vVUJQM06FQ0VEfuVLDw==", "dev": true, "dependencies": { - "@nx/cypress": "19.1.0" + "@nx/cypress": "19.1.1" } }, "node_modules/@nrwl/devkit": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.0.tgz", - "integrity": "sha512-n4YxtAMSdlXAmwcSKcLEX48kpcPGI/sX7lCfDeoSnTKud8Y1tlNeD8rf0YZV3ae+srE6j4lxfoJrRCpWweMcEQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", "dev": true, "dependencies": { - "@nx/devkit": "19.1.0" + "@nx/devkit": "19.1.1" } }, "node_modules/@nrwl/eslint-plugin-nx": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/eslint-plugin-nx/-/eslint-plugin-nx-19.1.0.tgz", - "integrity": "sha512-ZH34DlUoWD7p9aDVu3Uor/+jROqEfBGI+XIzBLDLjnmHkobsFwmvjbvDqvFeTMM3qvVJih1GfezbVRAhh2f4ZA==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/eslint-plugin-nx/-/eslint-plugin-nx-19.1.1.tgz", + "integrity": "sha512-IQYQ7vaCRysK8WOlK3xRJYqE/Rnnj4B69H/b4hPVQyV0IVUbHBcbKhOQftj8zdJyDAKqrXFxqMZ/hqvAvN6sXg==", "dev": true, "dependencies": { - "@nx/eslint-plugin": "19.1.0" + "@nx/eslint-plugin": "19.1.1" } }, "node_modules/@nrwl/express": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/express/-/express-19.1.0.tgz", - "integrity": "sha512-9C04Sls38dKbWK0tAP0ZGsa1C+k56kGamSi1WCZbrfyU5yFvaxSVCfU0AUNOMlv8RN2IktaOke17vqoIah0uUg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/express/-/express-19.1.1.tgz", + "integrity": "sha512-k7i9CijZscSJB2aRaKVNoHqKmTN21ZfMAcFbYNEPrLkv8zGqfX46Wdq/bOXqELStNc9MzeNMxycqDXKSR9r1kA==", "dev": true, "dependencies": { - "@nx/express": "19.1.0" + "@nx/express": "19.1.1" } }, "node_modules/@nrwl/jest": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/jest/-/jest-19.1.0.tgz", - "integrity": "sha512-UZzpxvmF411xlvYF0lNOddLn0ZSCmqF4sn21W3touPEvQZglszUFR5BKnuk/A2Me86wpKOiJUMeNp8GpL6pGUQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/jest/-/jest-19.1.1.tgz", + "integrity": "sha512-hpWLl05iN9f9fUnlyOqihTG7mU+yjQEQ+TsrSAx9mjwvTohHJCp9pDx10620uBD7nzIjpjienHYIn3fWVyHDhw==", "dev": true, "dependencies": { - "@nx/jest": "19.1.0" + "@nx/jest": "19.1.1" } }, "node_modules/@nrwl/js": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/js/-/js-19.1.0.tgz", - "integrity": "sha512-bzjHWDwOpQ/Xju6Kei4MFOJvsO6zhoHE94IRKJobj2yLewy0P2gStyp05XOE/bMpY4GJ6ggthINkaxgl6ae0DA==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/js/-/js-19.1.1.tgz", + "integrity": "sha512-MiQJeb/GcVcRj0DibOIQuQOgDsE6js7TGJZ0zTOydviTWc8YDyHSutVnpYvUzrrEtDyN5DdDvFYkscggBdCjpg==", "dev": true, "dependencies": { - "@nx/js": "19.1.0" + "@nx/js": "19.1.1" } }, "node_modules/@nrwl/node": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/node/-/node-19.1.0.tgz", - "integrity": "sha512-5OtiR7t+9VaY+wBuEMy0fMTC/a2tQEKBbnOKbxgcVKBg7rabLDu0yxUTdpbHRcfJC1YWTQzj4tnXANnmXe7bwQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/node/-/node-19.1.1.tgz", + "integrity": "sha512-AKnLdm0YWYFNr2b2bx4+vW3khzS0npL9v4s7LlDRiS78p6Ncbz70hc6Db3mRU55aYG0/TRWrSzUgFoSXPF855A==", "dev": true, "dependencies": { - "@nx/node": "19.1.0" + "@nx/node": "19.1.1" } }, "node_modules/@nrwl/tao": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.1.0.tgz", - "integrity": "sha512-Mayqkuh2EXkac5prri5fQFd19RBRxBQRjVwTcezk7yTKWI7V+bJzbgZANybtcKGsPCH34cpqrlV4inVwtyaVzw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.1.1.tgz", + "integrity": "sha512-03iaf+rnOEf5HHLsiSA7QIk63mBtcU4vkqkggoYLxJpMthx5nD4Z12nk+G/Z5RKWYUG4k3j6G7CFiIQRYOy7TA==", "dev": true, "dependencies": { - "nx": "19.1.0", + "nx": "19.1.1", "tslib": "^2.3.0" }, "bin": { @@ -3833,39 +3833,39 @@ } }, "node_modules/@nrwl/vite": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/vite/-/vite-19.1.0.tgz", - "integrity": "sha512-BsLO2yzstH7637iIDbcguh60/2oTDU/cbUs6sHvJ5Cgetes2zkbPTdLhWa+ID6/saudUzT7Vugke4G5n5VCaFQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/vite/-/vite-19.1.1.tgz", + "integrity": "sha512-M98R4izmiz6Ck1lgLJM7dtTSBJ+uQJif5YAQvgyPrI5SIj2ECTpy4upZtNRlZhUd1k6sfc+lWXHzDhhkA/dJew==", "dev": true, "dependencies": { - "@nx/vite": "19.1.0" + "@nx/vite": "19.1.1" } }, "node_modules/@nrwl/web": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/web/-/web-19.1.0.tgz", - "integrity": "sha512-46V8VR0BUP/PJ2k+2BMxh+xzlew7UwI+xbMAXKcBwRSPHJXipuqQuVfnGMl5HRIKf1fxXtRuvDtx0qQjSzNxMA==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/web/-/web-19.1.1.tgz", + "integrity": "sha512-g3OebUaNpq5+zYMrZLbLyixXG3fKjjQndxZyStr8Uwxdi4xWIy5zp9wP6zrScqHif8HKtsnKINCueRQEXBpfjA==", "dev": true, "dependencies": { - "@nx/web": "19.1.0" + "@nx/web": "19.1.1" } }, "node_modules/@nrwl/webpack": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/webpack/-/webpack-19.1.0.tgz", - "integrity": "sha512-vGeLnvsaBM2M+zroMsCFqqjEcY4TaOrnFGqPUFOT6T019S+b1/1AmSK+GQOVake90/klpR2T/p8WcdCDvzqkvw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/webpack/-/webpack-19.1.1.tgz", + "integrity": "sha512-fVOceYltxitpyd5wdUXip8QGBMC4IIm43nLbNxkMkmXuZTVxjxmYzGJOABLVSi5JFFpOBowlek7USEcMb77Eow==", "dev": true, "dependencies": { - "@nx/webpack": "19.1.0" + "@nx/webpack": "19.1.1" } }, "node_modules/@nrwl/workspace": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nrwl/workspace/-/workspace-19.1.0.tgz", - "integrity": "sha512-NSscB84tRn0VRmqZ3W8Zn+tnowCrF0TNCNq8cTFLRqzmg8/kyKrJMEMJmUwPPR9F1u66ciYkbGPbGwGVlEGQSw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/workspace/-/workspace-19.1.1.tgz", + "integrity": "sha512-lWmz9tVX1ShKOugdn/A0PbP40Pzq5MsWdkLMwpiKCZLF4WMNzX+cb5W05VvCagHKRAovgZT9Ao9qY2CTD9482Q==", "dev": true, "dependencies": { - "@nx/workspace": "19.1.0" + "@nx/workspace": "19.1.1" } }, "node_modules/@nx-tools/ci-context": { @@ -3940,15 +3940,15 @@ } }, "node_modules/@nx/cypress": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/cypress/-/cypress-19.1.0.tgz", - "integrity": "sha512-sxXhRv7/FJ+e9nWx0Vm+eS7nCUksvBwye5iSq4/DtSLgnYAP9OzQ+zEbAkD2SJdE3VFDrNK+kCSUcwip1mn3zw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/cypress/-/cypress-19.1.1.tgz", + "integrity": "sha512-kGQrwGnBSy+68i1UojgTkTiByYeqbgee8x1Aalw7WQGJU8e9euFD7Wvd1evfJ1IL1Tx2knMXEHwmJKp7sYoXvQ==", "dev": true, "dependencies": { - "@nrwl/cypress": "19.1.0", - "@nx/devkit": "19.1.0", - "@nx/eslint": "19.1.0", - "@nx/js": "19.1.0", + "@nrwl/cypress": "19.1.1", + "@nx/devkit": "19.1.1", + "@nx/eslint": "19.1.1", + "@nx/js": "19.1.1", "@phenomnomnominal/tsquery": "~5.0.1", "detect-port": "^1.5.1", "tslib": "^2.3.0" @@ -3963,12 +3963,12 @@ } }, "node_modules/@nx/devkit": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.0.tgz", - "integrity": "sha512-jn8uNgavpRhYZ1u63YFNWc2lEoAr3YA7bvPK9yaBmV++tFj+Ig+eFKkQxRou4tvOUnIyVPrs/fmi/TBLVQcpQg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", "dev": true, "dependencies": { - "@nrwl/devkit": "19.1.0", + "@nrwl/devkit": "19.1.1", "ejs": "^3.1.7", "enquirer": "~2.3.6", "ignore": "^5.0.4", @@ -3983,14 +3983,14 @@ } }, "node_modules/@nx/eslint": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/eslint/-/eslint-19.1.0.tgz", - "integrity": "sha512-UIeNUyUw9Dq21dXP+0vXplOtowgcWET7WnOLP9p4FD9LVMAS0mlR8noVwHjo6V9YgGhGisfzr/DFlJB7xqEDEw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/eslint/-/eslint-19.1.1.tgz", + "integrity": "sha512-okmq9o/o3zqvDXFz1xqfcQ0Skmbvo3xMkAsacjuYP8W9kNVsRKFGqzI55lMTbvTYNDeFE30mcHLSpwzkgIm43g==", "dev": true, "dependencies": { - "@nx/devkit": "19.1.0", - "@nx/js": "19.1.0", - "@nx/linter": "19.1.0", + "@nx/devkit": "19.1.1", + "@nx/js": "19.1.1", + "@nx/linter": "19.1.1", "semver": "^7.5.3", "tslib": "^2.3.0", "typescript": "~5.4.2" @@ -4006,14 +4006,14 @@ } }, "node_modules/@nx/eslint-plugin": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/eslint-plugin/-/eslint-plugin-19.1.0.tgz", - "integrity": "sha512-lLWJvBCvpREBFIxNWk+d1Xfoe0RqH2+v6fkZB/pk/n/q9mHPvSE7JwFMxIw+QrIguAxKhAHGqDskTRH4llzz6w==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/eslint-plugin/-/eslint-plugin-19.1.1.tgz", + "integrity": "sha512-ae+rkkiuW2iNJpVO29foI04eIaz+H/hPkosUBTf6PdJ4XtRGtACA1O7MhJckxB2MGDQc7A3+OvtEIj2wEjBfvw==", "dev": true, "dependencies": { - "@nrwl/eslint-plugin-nx": "19.1.0", - "@nx/devkit": "19.1.0", - "@nx/js": "19.1.0", + "@nrwl/eslint-plugin-nx": "19.1.1", + "@nx/devkit": "19.1.1", + "@nx/js": "19.1.1", "@typescript-eslint/type-utils": "^7.3.0", "@typescript-eslint/utils": "^7.3.0", "chalk": "^4.1.0", @@ -4033,14 +4033,14 @@ } }, "node_modules/@nx/express": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/express/-/express-19.1.0.tgz", - "integrity": "sha512-tXl/egth9UNnS+kSI0G1dhFnsvh4s8bHc8tecmQvBLjeoP5J5okEKlDF0Fzi5ipd4IQMZlKCpbMI5ANhe1Dddg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/express/-/express-19.1.1.tgz", + "integrity": "sha512-DZdqe+IeOezKoT7EyDYSRylrdjGtKPJUCVwSxRmNP5eVr5ocCtBtJY5ANVymvkx1RTwWKdIFmoT5+7AXSqxdyg==", "dev": true, "dependencies": { - "@nrwl/express": "19.1.0", - "@nx/devkit": "19.1.0", - "@nx/node": "19.1.0", + "@nrwl/express": "19.1.1", + "@nx/devkit": "19.1.1", + "@nx/node": "19.1.1", "tslib": "^2.3.0" }, "peerDependencies": { @@ -4053,16 +4053,16 @@ } }, "node_modules/@nx/jest": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/jest/-/jest-19.1.0.tgz", - "integrity": "sha512-US8oW/ZvRnVE47kTqGveuCd8A4z66qNOCcFAvtDuzHDPXn7BOOf7ZIPsAheSyIUIkzu2xr4Efb6YsuFub9p9fQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/jest/-/jest-19.1.1.tgz", + "integrity": "sha512-DlGfav1zbCHt5esX58URgR+i4ElWO7hRikQsW4RF6DLFoxRKjjr9nbwgV7BeCe8DjTbFrOh4eQDx1UiqBRmNTA==", "dev": true, "dependencies": { "@jest/reporters": "^29.4.1", "@jest/test-result": "^29.4.1", - "@nrwl/jest": "19.1.0", - "@nx/devkit": "19.1.0", - "@nx/js": "19.1.0", + "@nrwl/jest": "19.1.1", + "@nx/devkit": "19.1.1", + "@nx/js": "19.1.1", "@phenomnomnominal/tsquery": "~5.0.1", "chalk": "^4.1.0", "identity-obj-proxy": "3.0.0", @@ -4076,9 +4076,9 @@ } }, "node_modules/@nx/js": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/js/-/js-19.1.0.tgz", - "integrity": "sha512-szEmGGMYMsl57LVe80V9ZAp8BIo41cQf11DGe72J2tHXVi2H7+hGN6VA0dqGWxfffbpHJyIDy/NXpB4Y0z1vPw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/js/-/js-19.1.1.tgz", + "integrity": "sha512-i8jXT7u6q9McV0mlEwvgN6WAa28FDdBI+45xNF1UApag892qzGjLu81xjrfTYlmF3tcP7xG7DUfqCU5oAoEcXg==", "dev": true, "dependencies": { "@babel/core": "^7.23.2", @@ -4088,9 +4088,9 @@ "@babel/preset-env": "^7.23.2", "@babel/preset-typescript": "^7.22.5", "@babel/runtime": "^7.22.6", - "@nrwl/js": "19.1.0", - "@nx/devkit": "19.1.0", - "@nx/workspace": "19.1.0", + "@nrwl/js": "19.1.1", + "@nx/devkit": "19.1.1", + "@nx/workspace": "19.1.1", "babel-plugin-const-enum": "^1.0.1", "babel-plugin-macros": "^2.8.0", "babel-plugin-transform-typescript-metadata": "^0.3.1", @@ -4164,32 +4164,32 @@ } }, "node_modules/@nx/linter": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/linter/-/linter-19.1.0.tgz", - "integrity": "sha512-se8akeKL7AHimBdE3ucVtWFi6fWwe8u0wkN6TOzS0IUDVS6JoCRwbbIhPy9yQYFtUokBxg/h/aVthwGwMMNWgw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/linter/-/linter-19.1.1.tgz", + "integrity": "sha512-xx8fpJTlT4EIDweaYrknD5e5V5PsAO1Vr5lNG01gfQ0oB1B/ewU8h7jMnMGOJ2QTRtv8kEb3FAR38W1oLG2Q2g==", "dev": true, "dependencies": { - "@nx/eslint": "19.1.0" + "@nx/eslint": "19.1.1" } }, "node_modules/@nx/node": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/node/-/node-19.1.0.tgz", - "integrity": "sha512-o37kzx9R4PAxLE4aNaZfb8+4d/g6XW3lPDXC3s/YcgNxfA0KeUga3LtU2jOlMBI0ToeDnqor6QqZ3NbwA3f53Q==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/node/-/node-19.1.1.tgz", + "integrity": "sha512-szy7EQQI5LzfxM17GxTNPzDvHoIUqvgN2Z+UUy8r82OC/DTdmQnRpaZFb3UHSTh/v7lXgKukwcb03uw060woTg==", "dev": true, "dependencies": { - "@nrwl/node": "19.1.0", - "@nx/devkit": "19.1.0", - "@nx/eslint": "19.1.0", - "@nx/jest": "19.1.0", - "@nx/js": "19.1.0", + "@nrwl/node": "19.1.1", + "@nx/devkit": "19.1.1", + "@nx/eslint": "19.1.1", + "@nx/jest": "19.1.1", + "@nx/js": "19.1.1", "tslib": "^2.3.0" } }, "node_modules/@nx/nx-darwin-arm64": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.1.0.tgz", - "integrity": "sha512-qUPZmVusnYrgqwhIYKBbabB1RpVQZiTcKfBdW1XiBTk+dXOuIVyWVCsg2ohoBJpHJiENYjtCprxR3RWPaxFs5Q==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.1.1.tgz", + "integrity": "sha512-5CcgmNhUg5N62zCuzNZfRRPvaLRZNhLk0OkpMa085atEshM8RUAMbN80ffINaBssYtKu6znJ9LhUK+q7C3KiFQ==", "cpu": [ "arm64" ], @@ -4203,9 +4203,9 @@ } }, "node_modules/@nx/nx-darwin-x64": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.1.0.tgz", - "integrity": "sha512-0Gf45EQTq8Q9/inGDzX5SqNY4jXDtqqVsz6wAJ07M9CeyjwDIXOzPe36uoMUhcvXQMbMp3QUH2E/X9poxOOubg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.1.1.tgz", + "integrity": "sha512-vDM9vZow3YLA3+7GKTqhtguNcbQPifMTbqm8Aevd/suqCChQsLyD1Hh1Z+o03RNolNTRacNb6GPvoKFY4BJ2tA==", "cpu": [ "x64" ], @@ -4219,9 +4219,9 @@ } }, "node_modules/@nx/nx-freebsd-x64": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.1.0.tgz", - "integrity": "sha512-bw3sKpXy1R17OTStOkeRUE4EkPsvXjAEp26qmKX3G7a7bCVjH7cn+UXdgF8jsEyyiqb8WY1LG63abIlbyfecIA==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.1.1.tgz", + "integrity": "sha512-FfOBrc1vndWYXSZVgbB9nWRp8/jo7f9b3g3ZfqaVwsGpcYcwz7dxiPV7HQKysTR0WNVv1aTi2Dg1CF+F94qlPw==", "cpu": [ "x64" ], @@ -4235,9 +4235,9 @@ } }, "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.1.0.tgz", - "integrity": "sha512-jJzkPWptqFnl7Q7clTMGvI6OT1x8Jw7JHLCi6JgKBqb2ieF4vUCUsLHkrfS/95l9hCUeIHeBrfHJxEXLZIhOgQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.1.1.tgz", + "integrity": "sha512-Bb94MmoOsPnTI4n1mrILSwGmx9I50LEkEOgksoiOEYdykWKjbz6z4ZnFCJHTeF0bca1OmF5iCjFWU42KlLUsRQ==", "cpu": [ "arm" ], @@ -4251,9 +4251,9 @@ } }, "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.1.0.tgz", - "integrity": "sha512-zycD7+PbVStbjlPsxE3G+bdwFDzXE7LKWtQOrGLvBxG99pXbTr+Oq1GtqL68p2Jp4MEYjIO5qdxWdNt9bBsSwA==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.1.1.tgz", + "integrity": "sha512-mqiRi95LOUTWldtif3f2aJOFLxg/2jnM1UYj85vUlaLZJmQK64OhQslCAAZCmEWkHAYqEooHaYqj30YmDb92jw==", "cpu": [ "arm64" ], @@ -4267,9 +4267,9 @@ } }, "node_modules/@nx/nx-linux-arm64-musl": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.1.0.tgz", - "integrity": "sha512-NBUUbj/3NXHrqgkoLdMTnd8e9qduRVcSoGqpYDha0HBFc+Fspacw5+U26LjnmIuk/BT4yMtMrgFKU29Rq1a56w==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.1.1.tgz", + "integrity": "sha512-lhyVsuT19Ez4ynhen6dT+Zdq2cABXcphYSkVSASvZGvka/65AS+0D1hX0TFDPJvbTdsHwVszJQZzIqGmYUkhLA==", "cpu": [ "arm64" ], @@ -4283,9 +4283,9 @@ } }, "node_modules/@nx/nx-linux-x64-gnu": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.1.0.tgz", - "integrity": "sha512-jaPrd1VIdz/dqcjEKUJ5BnU+ONSZmG1G/g1HrNb+SIl3Ztputrwz8yJ7CwpUryRo+xSwWhZXIiNJ5r7z09kaKw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.1.1.tgz", + "integrity": "sha512-zUQhMwz/gQ0up1iymwTqXbyLJca87HXOP+uAD5wfgarh0yhPDwcGaVsV8O8t2z8W/dH/yYmuppe3gAwsvd5SSg==", "cpu": [ "x64" ], @@ -4299,9 +4299,9 @@ } }, "node_modules/@nx/nx-linux-x64-musl": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.1.0.tgz", - "integrity": "sha512-gj3Bq81s1NWzjtWteyTgczbbd2yq6xmic4H3PGFZkA5THjFAD/MiYiS9b5oQVzPWONyFgtk+gsTWVbiM7dOhew==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.1.1.tgz", + "integrity": "sha512-3Gc2iwMbFAp50OlIqfgryTtZno/FqPW+AOP1Pijo/jJOZ8DHP3A7Zy8QoJYUgTQxCffzVbhshXW6yy403pV3OQ==", "cpu": [ "x64" ], @@ -4315,9 +4315,9 @@ } }, "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.1.0.tgz", - "integrity": "sha512-PIGy+uu8dzhWodIHXC0jbPtYcpi95NdtkghD1yZ32jcoVzAcHOohM07tTMHXbl7WyLqXw+De0XkmZadMJoVNAg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.1.1.tgz", + "integrity": "sha512-91LJG0triTdZDHnT9l1N1YuIwhmR7iCbKsEv345OdPhHJeQ6GAuJCD0SqDk6aZ13xr7LoRlS8c6bnfctXeslQQ==", "cpu": [ "arm64" ], @@ -4331,9 +4331,9 @@ } }, "node_modules/@nx/nx-win32-x64-msvc": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.1.0.tgz", - "integrity": "sha512-aTbwZLIpViWgMZqyDl+2fyO5LJjtz0J4a0+0qPpEW46BAZ/kcEuE7Xv33Yoob+KorLr27n6BpzTs+7Wg4dXXFw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.1.1.tgz", + "integrity": "sha512-rEWRqcW1osCeaZ9KPfZWARIdOHGd0WXRW6iqqRvZZEAIbGlZP/89Sj2o9Fvs5oHpng7kfrqsDbpbikmmlX7HTQ==", "cpu": [ "x64" ], @@ -4347,14 +4347,14 @@ } }, "node_modules/@nx/vite": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/vite/-/vite-19.1.0.tgz", - "integrity": "sha512-5m7anx2gmSX9QFG4qmz+sckHsBroV0zdyGW1k1q9P2mYyobVHF93Plw7HieixnAgDqMV2Qnf8MBSdXj31bkSEA==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/vite/-/vite-19.1.1.tgz", + "integrity": "sha512-P1APiRpRN3wpVNcgBejMokaoVhBDTThyu5hRSRRymI64Bw6kLxhQyGm8C2vZULMmrQFfgBvXAaCcJ8uNH1WFFw==", "dev": true, "dependencies": { - "@nrwl/vite": "19.1.0", - "@nx/devkit": "19.1.0", - "@nx/js": "19.1.0", + "@nrwl/vite": "19.1.1", + "@nx/devkit": "19.1.1", + "@nx/js": "19.1.1", "@phenomnomnominal/tsquery": "~5.0.1", "@swc/helpers": "~0.5.0", "enquirer": "~2.3.6", @@ -4366,14 +4366,14 @@ } }, "node_modules/@nx/web": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/web/-/web-19.1.0.tgz", - "integrity": "sha512-9t9QyVB8VPWDJmh5NdTnWwAghCkjS9F4rhKcN+oI3gD7CXFYkRkr9y/RPnfc+RlT9aapA67do2hwgY8ZVw43vw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/web/-/web-19.1.1.tgz", + "integrity": "sha512-PEmBQy2WxzGmhMb8OxOARAys+6B24RBBgmqpN1YBzPLDoTeyi5M/HqjHqD5LE6WgywfIazGrCgkFa8+XxqnFlg==", "dev": true, "dependencies": { - "@nrwl/web": "19.1.0", - "@nx/devkit": "19.1.0", - "@nx/js": "19.1.0", + "@nrwl/web": "19.1.1", + "@nx/devkit": "19.1.1", + "@nx/js": "19.1.1", "chalk": "^4.1.0", "detect-port": "^1.5.1", "http-server": "^14.1.0", @@ -4381,15 +4381,15 @@ } }, "node_modules/@nx/webpack": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/webpack/-/webpack-19.1.0.tgz", - "integrity": "sha512-9bs1efN6PCTDJiDcYGiCd5baZbyjglBYxPevMIVLjs5Otds2PGNWcTnZaqGrIK23l8eTm1j8KbevFvc88i6X0Q==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/webpack/-/webpack-19.1.1.tgz", + "integrity": "sha512-SwGcWSNstZoGOM91Y623YIy2Zf3d+kyzMX8QJs/RKVJ4LGJ9cfevRNNlWnWmV4kuS+GHuhXcwR1xmlCppImhVQ==", "dev": true, "dependencies": { "@babel/core": "^7.23.2", - "@nrwl/webpack": "19.1.0", - "@nx/devkit": "19.1.0", - "@nx/js": "19.1.0", + "@nrwl/webpack": "19.1.1", + "@nx/devkit": "19.1.1", + "@nx/js": "19.1.1", "ajv": "^8.12.0", "autoprefixer": "^10.4.9", "babel-loader": "^9.1.2", @@ -4426,16 +4426,16 @@ } }, "node_modules/@nx/workspace": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-19.1.0.tgz", - "integrity": "sha512-1W+zwRP4Uma0Ui0Za8qcd0rAt4InaLZ3yfAN66MaqQlyIPMsJDSqLBAVKEJfn4wS7zgoeeIwmQoXi6ACLKqZZA==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-19.1.1.tgz", + "integrity": "sha512-aTOAGotI8tbQiYp1jx+n0+SK18fpmPeRNA95y7xH8uMZLcm7zfOZiE0r450nbAVwU62JWncCvxwdB2weBVkY4w==", "dev": true, "dependencies": { - "@nrwl/workspace": "19.1.0", - "@nx/devkit": "19.1.0", + "@nrwl/workspace": "19.1.1", + "@nx/devkit": "19.1.1", "chalk": "^4.1.0", "enquirer": "~2.3.6", - "nx": "19.1.0", + "nx": "19.1.1", "tslib": "^2.3.0", "yargs-parser": "21.1.1" } @@ -5121,9 +5121,9 @@ } }, "node_modules/@stencil/core": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.18.2.tgz", - "integrity": "sha512-GLYbzv3Bq/oUbQk3CH09zkjISANccyE5/A1C7+1JZhdnWUx1MRuWQR9/2uzSPR7kF0sdppwzXvArl7VqYCxLOQ==", + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.18.3.tgz", + "integrity": "sha512-8yoG5AFQYEPocVtuoc5kvRS0Hku0MoDWDUpADRaXPVHsOFLmxR16LJENj25ucCz5GEfeTGQ/tCE8JAypPmr/fQ==", "bin": { "stencil": "bin/stencil" }, @@ -5188,13 +5188,13 @@ } }, "node_modules/@swc/core": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.7.tgz", - "integrity": "sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==", + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.24.tgz", + "integrity": "sha512-Eph9zvO4xvqWZGVzTdtdEJ0Vqf0VIML/o/e4Qd2RLOqtfgnlRi7avmMu5C0oqciJ0tk+hqdUKVUZ4JPoPaiGvQ==", "hasInstallScript": true, "dependencies": { - "@swc/counter": "^0.1.2", - "@swc/types": "0.1.7" + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.7" }, "engines": { "node": ">=10" @@ -5204,19 +5204,19 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.5.7", - "@swc/core-darwin-x64": "1.5.7", - "@swc/core-linux-arm-gnueabihf": "1.5.7", - "@swc/core-linux-arm64-gnu": "1.5.7", - "@swc/core-linux-arm64-musl": "1.5.7", - "@swc/core-linux-x64-gnu": "1.5.7", - "@swc/core-linux-x64-musl": "1.5.7", - "@swc/core-win32-arm64-msvc": "1.5.7", - "@swc/core-win32-ia32-msvc": "1.5.7", - "@swc/core-win32-x64-msvc": "1.5.7" + "@swc/core-darwin-arm64": "1.5.24", + "@swc/core-darwin-x64": "1.5.24", + "@swc/core-linux-arm-gnueabihf": "1.5.24", + "@swc/core-linux-arm64-gnu": "1.5.24", + "@swc/core-linux-arm64-musl": "1.5.24", + "@swc/core-linux-x64-gnu": "1.5.24", + "@swc/core-linux-x64-musl": "1.5.24", + "@swc/core-win32-arm64-msvc": "1.5.24", + "@swc/core-win32-ia32-msvc": "1.5.24", + "@swc/core-win32-x64-msvc": "1.5.24" }, "peerDependencies": { - "@swc/helpers": "^0.5.0" + "@swc/helpers": "*" }, "peerDependenciesMeta": { "@swc/helpers": { @@ -5225,9 +5225,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.7.tgz", - "integrity": "sha512-bZLVHPTpH3h6yhwVl395k0Mtx8v6CGhq5r4KQdAoPbADU974Mauz1b6ViHAJ74O0IVE5vyy7tD3OpkQxL/vMDQ==", + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.24.tgz", + "integrity": "sha512-M7oLOcC0sw+UTyAuL/9uyB9GeO4ZpaBbH76JSH6g1m0/yg7LYJZGRmplhDmwVSDAR5Fq4Sjoi1CksmmGkgihGA==", "cpu": [ "arm64" ], @@ -5240,9 +5240,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.7.tgz", - "integrity": "sha512-RpUyu2GsviwTc2qVajPL0l8nf2vKj5wzO3WkLSHAHEJbiUZk83NJrZd1RVbEknIMO7+Uyjh54hEh8R26jSByaw==", + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.24.tgz", + "integrity": "sha512-MfcFjGGYognpSBSos2pYUNYJSmqEhuw5ceGr6qAdME7ddbjGXliza4W6FggsM+JnWwpqa31+e7/R+GetW4WkaQ==", "cpu": [ "x64" ], @@ -5255,9 +5255,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.7.tgz", - "integrity": "sha512-cTZWTnCXLABOuvWiv6nQQM0hP6ZWEkzdgDvztgHI/+u/MvtzJBN5lBQ2lue/9sSFYLMqzqff5EHKlFtrJCA9dQ==", + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.24.tgz", + "integrity": "sha512-amI2pwtcWV3E/m/nf+AQtn1LWDzKLZyjCmWd3ms7QjEueWYrY8cU1Y4Wp7wNNsxIoPOi8zek1Uj2wwFD/pttNQ==", "cpu": [ "arm" ], @@ -5270,9 +5270,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.7.tgz", - "integrity": "sha512-hoeTJFBiE/IJP30Be7djWF8Q5KVgkbDtjySmvYLg9P94bHg9TJPSQoC72tXx/oXOgXvElDe/GMybru0UxhKx4g==", + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.24.tgz", + "integrity": "sha512-sTSvmqMmgT1ynH/nP75Pc51s+iT4crZagHBiDOf5cq+kudUYjda9lWMs7xkXB/TUKFHPCRK0HGunl8bkwiIbuw==", "cpu": [ "arm64" ], @@ -5285,9 +5285,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.7.tgz", - "integrity": "sha512-+NDhK+IFTiVK1/o7EXdCeF2hEzCiaRSrb9zD7X2Z7inwWlxAntcSuzZW7Y6BRqGQH89KA91qYgwbnjgTQ22PiQ==", + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.24.tgz", + "integrity": "sha512-vd2/hfOBGbrX21FxsFdXCUaffjkHvlZkeE2UMRajdXifwv79jqOHIJg3jXG1F3ZrhCghCzirFts4tAZgcG8XWg==", "cpu": [ "arm64" ], @@ -5300,9 +5300,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.7.tgz", - "integrity": "sha512-25GXpJmeFxKB+7pbY7YQLhWWjkYlR+kHz5I3j9WRl3Lp4v4UD67OGXwPe+DIcHqcouA1fhLhsgHJWtsaNOMBNg==", + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.24.tgz", + "integrity": "sha512-Zrdzi7NqzQxm2BvAG5KyOSBEggQ7ayrxh599AqqevJmsUXJ8o2nMiWQOBvgCGp7ye+Biz3pvZn1EnRzAp+TpUg==", "cpu": [ "x64" ], @@ -5315,9 +5315,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.7.tgz", - "integrity": "sha512-0VN9Y5EAPBESmSPPsCJzplZHV26akC0sIgd3Hc/7S/1GkSMoeuVL+V9vt+F/cCuzr4VidzSkqftdP3qEIsXSpg==", + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.24.tgz", + "integrity": "sha512-1F8z9NRi52jdZQCGc5sflwYSctL6omxiVmIFVp8TC9nngjQKc00TtX/JC2Eo2HwvgupkFVl5YQJidAck9YtmJw==", "cpu": [ "x64" ], @@ -5330,9 +5330,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.7.tgz", - "integrity": "sha512-RtoNnstBwy5VloNCvmvYNApkTmuCe4sNcoYWpmY7C1+bPR+6SOo8im1G6/FpNem8AR5fcZCmXHWQ+EUmRWJyuA==", + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.24.tgz", + "integrity": "sha512-cKpP7KvS6Xr0jFSTBXY53HZX/YfomK5EMQYpCVDOvfsZeYHN20sQSKXfpVLvA/q2igVt1zzy1XJcOhpJcgiKLg==", "cpu": [ "arm64" ], @@ -5345,9 +5345,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.7.tgz", - "integrity": "sha512-Xm0TfvcmmspvQg1s4+USL3x8D+YPAfX2JHygvxAnCJ0EHun8cm2zvfNBcsTlnwYb0ybFWXXY129aq1wgFC9TpQ==", + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.24.tgz", + "integrity": "sha512-IoPWfi0iwqjZuf7gE223+B97/ZwkKbu7qL5KzGP7g3hJrGSKAvv7eC5Y9r2iKKtLKyv5R/T6Ho0kFR/usi7rHw==", "cpu": [ "ia32" ], @@ -5360,9 +5360,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.7.tgz", - "integrity": "sha512-tp43WfJLCsKLQKBmjmY/0vv1slVywR5Q4qKjF5OIY8QijaEW7/8VwPyUyVoJZEnDgv9jKtUTG5PzqtIYPZGnyg==", + "version": "1.5.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.24.tgz", + "integrity": "sha512-zHgF2k1uVJL8KIW+PnVz1To4a3Cz9THbh2z2lbehaF/gKHugH4c3djBozU4das1v35KOqf5jWIEviBLql2wDLQ==", "cpu": [ "x64" ], @@ -5666,9 +5666,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.1.tgz", - "integrity": "sha512-ej0phymbFLoCB26dbbq5PGScsf2JAJ4IJHjG10LalgUV36XKTmA4GdA+PVllKvRk0sEKt64X8975qFnkSi0hqA==", + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.3.tgz", + "integrity": "sha512-KOzM7MhcBFlmnlr/fzISFF5vGWVSvN6fTd4T+ExOt08bA/dA5kpSzY52nMsI1KDFmUREpJelPYyuslLRSjjgCg==", "dev": true, "dependencies": { "@types/node": "*", @@ -5707,9 +5707,9 @@ } }, "node_modules/@types/gtag.js": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.19.tgz", - "integrity": "sha512-KHoDzrf9rSd0mooKN576PjExpdk/XRrNu4RQnmigsScSTSidwyOUe9kDrHz9UPKjiBrx2QEsSkexbJSgS0j72w==", + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.20.tgz", + "integrity": "sha512-wwAbk3SA2QeU67unN7zPxjEHmPmlXwZXZvQEpbEUQuMCRGgKyE1m6XDuTUA9b6pCGb/GqJmdfMOY5LuDjJSbbg==", "dev": true }, "node_modules/@types/html-minifier": { @@ -6791,9 +6791,9 @@ } }, "node_modules/@zip.js/zip.js": { - "version": "2.7.44", - "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.44.tgz", - "integrity": "sha512-ZzMhAcAyRAYi1FZELsvKaw8I4ADxNTqbiVIjyo/syBe4HGWop9+OADnuBnHpm2TxgXPogxxhhPffOhDD40jUdA==", + "version": "2.7.45", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.45.tgz", + "integrity": "sha512-Mm2EXF33DJQ/3GWWEWeP1UCqzpQ5+fiMvT3QWspsXY05DyqqxWu7a9awSzU4/spHMHVFrTjani1PR0vprgZpow==", "engines": { "bun": ">=0.7.0", "deno": ">=1.0.0", @@ -7898,9 +7898,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001624", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001624.tgz", - "integrity": "sha512-0dWnQG87UevOCPYaOR49CBcLBwoZLpws+k6W37nLjWUhumP1Isusj0p2u+3KhjNloRWK9OKMgjBBzPujQHw4nA==", + "version": "1.0.30001625", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001625.tgz", + "integrity": "sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w==", "dev": true, "funding": [ { @@ -8024,9 +8024,9 @@ } }, "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, "engines": { "node": ">=6.0" @@ -9102,9 +9102,9 @@ "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -9562,9 +9562,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.783", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.783.tgz", - "integrity": "sha512-bT0jEz/Xz1fahQpbZ1D7LgmPYZ3iHVY39NcWWro1+hA2IvjiPeaXtfSqrQ+nXjApMvQRE2ASt1itSLRrebHMRQ==", + "version": "1.4.788", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.788.tgz", + "integrity": "sha512-ubp5+Ev/VV8KuRoWnfP2QF2Bg+O2ZFdb49DiiNbz2VmgkIqrnyYaqIOqj8A6K/3p1xV0QcU5hBQ1+BmB6ot1OA==", "dev": true }, "node_modules/elliptic": { @@ -9865,9 +9865,9 @@ } }, "node_modules/eslint-plugin-lit": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.13.0.tgz", - "integrity": "sha512-vKc67q6YQ+naYO1QuFpqMoTs3535yp8+0WB/8bzZRLr5NSOb4C6vZrD4se7S9XZtym5TxSVlIqa9QTWYISykQg==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.14.0.tgz", + "integrity": "sha512-J4w+CgO31621GreLFCdTUbTr5yeV2/RJ/M0myw0dykD5p9FGGIRLityQiNa6SG+JpVbmeQTQPJy4pNFmiurJ/w==", "dev": true, "dependencies": { "parse5": "^6.0.1", @@ -11493,9 +11493,9 @@ } }, "node_modules/google-gax": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.3.4.tgz", - "integrity": "sha512-upnobdflCz9+Lq9+nOv0pm9EQ+fLhWckz6lQTgLAkLAGggIH2fl+CUj0WgczdbhQDAnA0BSNfXYHglhA/dmZpw==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.3.5.tgz", + "integrity": "sha512-zXRSGgHp33ottCQMdYlKEFX/MhWkzKVX5P3Vpmx+DW6rtseLILzp3V0YV5Rh4oQzzkM0BH9+nJIyX01EUgmd3g==", "dependencies": { "@grpc/grpc-js": "~1.10.3", "@grpc/proto-loader": "^0.7.0", @@ -15131,13 +15131,13 @@ "dev": true }, "node_modules/nx": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/nx/-/nx-19.1.0.tgz", - "integrity": "sha512-ia9XIL4QWli02WNZ3tLSpWvIYJVOWcikeELJwouZOwHKT7RA9i6vCQjKsIKWSFlUs47WDwiYiLSsMxR5KTqk8Q==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/nx/-/nx-19.1.1.tgz", + "integrity": "sha512-9NPKoAQ+I3KcoFDThAVu7YznE9fKbV/AiE5dAXPbWfye9HjRdnhLQmXN122ADlq4pA5wkXwxvAxRLw2WA7Kkgw==", "dev": true, "hasInstallScript": true, "dependencies": { - "@nrwl/tao": "19.1.0", + "@nrwl/tao": "19.1.1", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "3.0.0-rc.46", "@zkochan/js-yaml": "0.0.7", @@ -15176,16 +15176,16 @@ "nx-cloud": "bin/nx-cloud.js" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "19.1.0", - "@nx/nx-darwin-x64": "19.1.0", - "@nx/nx-freebsd-x64": "19.1.0", - "@nx/nx-linux-arm-gnueabihf": "19.1.0", - "@nx/nx-linux-arm64-gnu": "19.1.0", - "@nx/nx-linux-arm64-musl": "19.1.0", - "@nx/nx-linux-x64-gnu": "19.1.0", - "@nx/nx-linux-x64-musl": "19.1.0", - "@nx/nx-win32-arm64-msvc": "19.1.0", - "@nx/nx-win32-x64-msvc": "19.1.0" + "@nx/nx-darwin-arm64": "19.1.1", + "@nx/nx-darwin-x64": "19.1.1", + "@nx/nx-freebsd-x64": "19.1.1", + "@nx/nx-linux-arm-gnueabihf": "19.1.1", + "@nx/nx-linux-arm64-gnu": "19.1.1", + "@nx/nx-linux-arm64-musl": "19.1.1", + "@nx/nx-linux-x64-gnu": "19.1.1", + "@nx/nx-linux-x64-musl": "19.1.1", + "@nx/nx-win32-arm64-msvc": "19.1.1", + "@nx/nx-win32-x64-msvc": "19.1.1" }, "peerDependencies": { "@swc-node/register": "^1.8.0", @@ -17338,9 +17338,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sass": { - "version": "1.77.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.2.tgz", - "integrity": "sha512-eb4GZt1C3avsX3heBNlrc7I09nyT00IUuo4eFhAbeXWU2fvA7oXI53SxODVAA+zgZCk9aunAZgO+losjR3fAwA==", + "version": "1.77.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.4.tgz", + "integrity": "sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", diff --git a/package.json b/package.json index 75405a6b..3f213d7e 100644 --- a/package.json +++ b/package.json @@ -19,17 +19,17 @@ "@esri/arcgis-rest-geocoding": "^4.0.2", "@esri/arcgis-rest-request": "^4.2.1", "@nx-tools/nx-container": "^6.0.1", - "@nx/cypress": "19.1.0", - "@nx/eslint": "19.1.0", - "@nx/eslint-plugin": "19.1.0", - "@nx/express": "19.1.0", - "@nx/jest": "19.1.0", - "@nx/js": "19.1.0", - "@nx/node": "19.1.0", - "@nx/vite": "19.1.0", - "@nx/web": "19.1.0", - "@nx/webpack": "19.1.0", - "@nx/workspace": "19.1.0", + "@nx/cypress": "19.1.1", + "@nx/eslint": "19.1.1", + "@nx/eslint-plugin": "19.1.1", + "@nx/express": "19.1.1", + "@nx/jest": "19.1.1", + "@nx/js": "19.1.1", + "@nx/node": "19.1.1", + "@nx/vite": "19.1.1", + "@nx/web": "19.1.1", + "@nx/webpack": "19.1.1", + "@nx/workspace": "19.1.1", "@protobuf-ts/plugin": "^2.9.4", "@swc/helpers": "~0.5.2", "@types/compression": "^1.7.5", @@ -39,7 +39,7 @@ "@types/express-fileupload": "^1.5.0", "@types/express-session": "^1.18.0", "@types/google.maps": "^3.55.9", - "@types/gtag.js": "^0.0.19", + "@types/gtag.js": "^0.0.20", "@types/ioredis": "^4.28.10", "@types/jest": "29.4.0", "@types/js-yaml": "^4.0.5", @@ -64,12 +64,12 @@ "jest-environment-node": "^29.4.1", "jsdom": "~22.1.0", "mailersend": "^2.2.0", - "nx": "19.1.0", + "nx": "19.1.1", "prettier": "^2.6.2", "rollup-plugin-minify-html-literals": "^1.2.6", "rollup-plugin-visualizer": "^5.12.0", - "servez": "^2.1.4", - "ts-jest": "^29.1.0", + "servez": "^2.1.6", + "ts-jest": "^29.1.4", "ts-node": "^10.9.2", "typescript": "5.4.5", "vite": "~5.0.0", @@ -83,7 +83,7 @@ "@dr.pogodin/csurf": "^1.13.0", "@google-cloud/compute": "^4.7.0", "@google-cloud/datastore": "^9.0.0", - "@google-cloud/pubsub": "^4.4.0", + "@google-cloud/pubsub": "^4.4.1", "@google-cloud/storage": "^7.11.1", "@googlemaps/js-api-loader": "^1.16.6", "@ionic/core": "^8.2.0", @@ -91,7 +91,7 @@ "@popperjs/core": "^2.11.8", "@protobuf-ts/runtime": "^2.9.4", "@reduxjs/toolkit": "^2.2.5", - "@stencil/core": "^4.18.2", + "@stencil/core": "^4.18.3", "@swc-node/register": "1.8.0", "@swc/core": "^1.3.95", "@tmcw/togeojson": "^5.8.1", @@ -111,7 +111,7 @@ "express-session": "^1.18.0", "geojson": "^0.5.0", "geolib": "^3.3.4", - "glob": "^10.3.15", + "glob": "^10.4.1", "google-polyline": "^1.0.3", "gpx-builder": "^5.3.0", "grant": "^5.4.22", From 80f59385668e4e9d135ae7351f22083f68b64921 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 3 Jun 2024 12:09:33 +0200 Subject: [PATCH 09/20] use structuredCloning --- apps/fxc-front/src/app/components/ui/main-menu.ts | 12 ++++++------ libs/optimizer/src/lib/optimizer.ts | 7 +++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/fxc-front/src/app/components/ui/main-menu.ts b/apps/fxc-front/src/app/components/ui/main-menu.ts index 823fb9cd..66591ad7 100644 --- a/apps/fxc-front/src/app/components/ui/main-menu.ts +++ b/apps/fxc-front/src/app/components/ui/main-menu.ts @@ -628,18 +628,18 @@ export class TrackItems extends connect(store)(LitElement) { (this.renderRoot.querySelector('#track') as HTMLInputElement)?.click(); } - private async handleUpload(e: Event): Promise { + private async handleUpload(e: Event & { target: HTMLInputElement }): Promise { if (e.target) { - const el = e.target as HTMLInputElement; - if (el.files?.length) { + const input = e.target; + if (input.files?.length) { const files: File[] = []; - for (let i = 0; i < el.files.length; i++) { - files.push(el.files[i]); + for (let i = 0; i < input.files.length; i++) { + files.push(input.files[i]); } const ids = await uploadTracks(files); pushCurrentState(); addUrlParamValues(ParamNames.groupId, ids); - el.value = ''; + input.value = ''; } } } diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index 2bffe644..28dcebb9 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -99,8 +99,7 @@ export function* getOptimizer( }; } const originalTrack = request.track; - const solverTrack = appendPointsIfNeeded(originalTrack, MIN_IGC_XC_SCORE_POINTS); - const flight = toIgcFile(solverTrack); + const flight = toIgcFile(appendPointsIfNeeded(originalTrack, MIN_IGC_XC_SCORE_POINTS)); const solverScoringRules = scoringRules.get(ruleName); const options = toSolverOptions(request); const solutionIterator = solver(flight, solverScoringRules || {}, options); @@ -120,13 +119,13 @@ export function* getOptimizer( * The points are close enough to the last point to not affect the score. */ function appendPointsIfNeeded(track: ScoringTrack, minValidLength: number) { + track = structuredClone(track); + if (track.points.length >= minValidLength) { return track; } // console.debug(`The track is too short, appending (${MIN_IGC_XC_SCORE_POINTS - track.points.length}) points`); - - track = JSON.parse(JSON.stringify(track)); while (track.points.length < minValidLength) { const lastPoint = track.points.at(-1)!; track.points.push({ From ba76ae27658d5c0512cfdac6c50231b20147a628 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 3 Jun 2024 12:10:14 +0200 Subject: [PATCH 10/20] fix jsdoc returns tag --- libs/optimizer/src/lib/optimizer.ts | 2 +- libs/optimizer/src/lib/utils/create-segments.ts | 2 +- libs/optimizer/src/lib/utils/merge-tracks.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index 28dcebb9..2fd0d4e0 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -82,7 +82,7 @@ export interface ScoringResult { * * @param request Contains the tracks and options. * @param ruleName The ScoringRules to use. - * @return an Iterator of OptimizationResult + * @returns an Iterator of OptimizationResult */ export function* getOptimizer( request: ScoringRequest, diff --git a/libs/optimizer/src/lib/utils/create-segments.ts b/libs/optimizer/src/lib/utils/create-segments.ts index 43aa6af2..e2052a9e 100644 --- a/libs/optimizer/src/lib/utils/create-segments.ts +++ b/libs/optimizer/src/lib/utils/create-segments.ts @@ -5,7 +5,7 @@ import { LatLonAltTime, ScoringTrack } from '../optimizer'; * * Points are computed by a linear interpolation * - * @return a ScoringTrack of nbSegments + * @returns a ScoringTrack of nbSegments */ export function createSegments(startPoint: LatLonAltTime, endPoint: LatLonAltTime, nbSegments: number): ScoringTrack { const points: LatLonAltTime[] = []; diff --git a/libs/optimizer/src/lib/utils/merge-tracks.ts b/libs/optimizer/src/lib/utils/merge-tracks.ts index 79d0c33e..c20219ec 100644 --- a/libs/optimizer/src/lib/utils/merge-tracks.ts +++ b/libs/optimizer/src/lib/utils/merge-tracks.ts @@ -6,7 +6,7 @@ import { LatLonAltTime, ScoringTrack } from '../optimizer'; * Collapse end and start point of consecutive tracks when they match. * * @param tracks the tracks to concatenate - * @return a track + * @returns a track */ export function mergeTracks(...tracks: ScoringTrack[]): ScoringTrack { const points: LatLonAltTime[] = []; From a2f6e670f2edf93912dc9a8c065d948b60a6e750 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 3 Jun 2024 12:34:24 +0200 Subject: [PATCH 11/20] Use import type where applicable --- .eslintrc.json | 3 ++- apps/airspaces/src/app/create-geojson.ts | 2 +- apps/airspaces/src/app/parser/openaip.ts | 3 ++- apps/airspaces/src/app/parser/openair.ts | 3 ++- apps/airspaces/src/app/parser/parser.ts | 3 ++- apps/airspaces/src/app/upload-tiles-diff.ts | 3 ++- apps/fetcher/src/app/elevation/arcgis.ts | 2 +- apps/fetcher/src/app/elevation/elevation.ts | 3 ++- apps/fetcher/src/app/redis.ts | 9 ++++---- apps/fetcher/src/app/state/serialize.ts | 3 ++- apps/fetcher/src/app/state/state.ts | 2 +- apps/fetcher/src/app/state/sync.test.ts | 6 +++-- apps/fetcher/src/app/state/sync.ts | 7 +++--- apps/fetcher/src/app/trackers/flymaster.ts | 11 ++++++---- apps/fetcher/src/app/trackers/flyme.ts | 9 +++++--- apps/fetcher/src/app/trackers/inreach.ts | 9 +++++--- .../src/app/trackers/live-track.test.ts | 3 ++- apps/fetcher/src/app/trackers/live-track.ts | 3 ++- apps/fetcher/src/app/trackers/ogn-client.ts | 6 +++-- apps/fetcher/src/app/trackers/ogn-push.ts | 5 +++-- apps/fetcher/src/app/trackers/ogn.ts | 13 ++++++----- apps/fetcher/src/app/trackers/refresh.ts | 9 ++++---- apps/fetcher/src/app/trackers/skylines.ts | 11 ++++++---- apps/fetcher/src/app/trackers/spot.test.ts | 2 +- apps/fetcher/src/app/trackers/spot.ts | 11 ++++++---- apps/fetcher/src/app/trackers/tracker.ts | 5 +++-- .../fetcher/src/app/trackers/xcontest.test.ts | 3 ++- apps/fetcher/src/app/trackers/xcontest.ts | 11 ++++++---- apps/fetcher/src/app/trackers/zoleo.test.ts | 2 +- apps/fetcher/src/app/trackers/zoleo.ts | 14 +++++++----- apps/fetcher/src/app/ufos/aviant.ts | 9 +++++--- apps/fetcher/src/app/ufos/refresh.ts | 7 +++--- apps/fetcher/src/app/ufos/ufo.ts | 5 +++-- apps/fetcher/src/fetcher.ts | 4 ++-- .../src/app/components/2d/airspace-element.ts | 6 +++-- .../src/app/components/2d/controls-element.ts | 10 +++++---- .../src/app/components/2d/line-element.ts | 8 ++++--- .../src/app/components/2d/map-element.ts | 11 ++++++---- .../src/app/components/2d/marker-element.ts | 8 ++++--- .../src/app/components/2d/path-element.ts | 10 +++++---- .../src/app/components/2d/planner-element.ts | 8 ++++--- .../src/app/components/2d/skyways-element.ts | 8 ++++--- .../src/app/components/2d/tracking-element.ts | 12 ++++++---- .../app/components/3d/airspace3d-element.ts | 10 +++++---- .../app/components/3d/controls3d-element.ts | 10 +++++---- .../src/app/components/3d/line3d-element.ts | 8 ++++--- .../src/app/components/3d/map3d-element.ts | 14 +++++++----- .../src/app/components/3d/marker3d-element.ts | 8 ++++--- .../app/components/3d/skyways3d-element.ts | 8 ++++--- .../app/components/3d/tracking3d-element.ts | 22 +++++++++++-------- .../src/app/components/admin/admin-page.ts | 3 ++- .../app/components/archives/archives-page.ts | 6 +++-- .../src/app/components/chart-element.ts | 9 +++++--- .../src/app/components/dashboard-element.ts | 3 ++- .../app/components/devices/devices-page.ts | 3 ++- .../src/app/components/devices/elements.ts | 3 ++- .../src/app/components/loader-element.ts | 6 +++-- .../src/app/components/menu-element.ts | 3 ++- .../src/app/components/name-element.ts | 5 +++-- .../src/app/components/ui/about-modal.ts | 3 ++- .../src/app/components/ui/google-btn.ts | 3 ++- .../src/app/components/ui/live-modal.ts | 11 ++++++---- .../src/app/components/ui/main-menu.ts | 17 +++++++++----- .../src/app/components/ui/pref-modal.ts | 6 +++-- .../src/app/components/ui/share-modal.ts | 8 ++++--- .../src/app/components/ui/supporter-modal.ts | 3 ++- .../src/app/components/ui/track-modal.ts | 9 +++++--- .../src/app/components/ui/waypoint-modal.ts | 5 +++-- apps/fxc-front/src/app/gm/fai-sectors.ts | 2 +- apps/fxc-front/src/app/logic/airspaces.ts | 9 ++++---- apps/fxc-front/src/app/logic/elevation.ts | 2 +- .../src/app/logic/live-track-popup.ts | 3 ++- apps/fxc-front/src/app/logic/live-track.ts | 3 ++- apps/fxc-front/src/app/logic/messages.ts | 2 +- .../src/app/logic/score/league/leagues.ts | 2 +- .../fxc-front/src/app/redux/airspace-slice.ts | 3 ++- apps/fxc-front/src/app/redux/app-slice.ts | 3 ++- apps/fxc-front/src/app/redux/arcgis-slice.ts | 3 ++- apps/fxc-front/src/app/redux/browser-slice.ts | 3 ++- .../src/app/redux/live-track-slice.ts | 13 ++++++----- .../fxc-front/src/app/redux/location-slice.ts | 5 +++-- apps/fxc-front/src/app/redux/planner-slice.ts | 7 +++--- apps/fxc-front/src/app/redux/selectors.ts | 8 ++++--- apps/fxc-front/src/app/redux/skyways-slice.ts | 5 +++-- apps/fxc-front/src/app/redux/store.ts | 5 +++-- apps/fxc-front/src/app/redux/track-slice.ts | 10 +++++---- apps/fxc-front/src/app/redux/units-slice.ts | 6 +++-- apps/fxc-front/src/app/workers/track.ts | 3 ++- apps/fxc-front/src/env.d.ts | 2 +- apps/fxc-front/src/flyxc.ts | 10 +++++---- apps/fxc-server/src/app/parser/geojson.ts | 2 +- apps/fxc-server/src/app/parser/igc.ts | 2 +- apps/fxc-server/src/app/parser/kml.ts | 2 +- apps/fxc-server/src/app/parser/parser.ts | 5 +++-- apps/fxc-server/src/app/parser/trk.ts | 2 +- apps/fxc-server/src/app/routes/admin.ts | 5 +++-- apps/fxc-server/src/app/routes/live-track.ts | 10 +++++---- apps/fxc-server/src/app/routes/session.ts | 2 +- apps/fxc-server/src/app/routes/supporters.ts | 5 +++-- apps/fxc-server/src/app/routes/track.ts | 7 +++--- apps/fxc-server/src/app/routes/waypoints.ts | 3 ++- apps/fxc-server/src/app/routes/zoleo.ts | 8 ++++--- .../fxc-server/src/app/waypoints/waypoints.ts | 3 ++- apps/misc/src/app/email_inreach.ts | 3 ++- apps/misc/src/app/list_flymaster.ts | 2 +- apps/misc/src/app/list_trackers.ts | 4 ++-- apps/misc/src/app/list_tracks.ts | 5 +++-- apps/misc/src/app/migrate.ts | 8 ++++--- apps/proxy/src/main.ts | 3 ++- apps/run/src/app/airspace.ts | 10 +++++---- apps/run/src/app/altitude.ts | 6 +++-- apps/run/src/app/process.ts | 5 +++-- apps/run/src/main.ts | 3 ++- libs/common-node/src/lib/datastore.ts | 3 ++- libs/common-node/src/lib/live-track-entity.ts | 5 +++-- libs/common-node/src/lib/redis.ts | 3 ++- libs/common-node/src/lib/track-entity.ts | 6 +++-- libs/common-node/src/lib/validators.ts | 7 +++--- libs/common/src/lib/airspaces.ts | 4 ++-- libs/common/src/lib/aprs.test.ts | 3 ++- libs/common/src/lib/distance.ts | 2 +- libs/common/src/lib/live-track-entity.ts | 2 +- libs/common/src/lib/live-track.ts | 3 ++- libs/common/src/lib/models.ts | 6 +++-- libs/common/src/lib/proj.ts | 2 +- libs/optimizer/src/lib/optimizer.spec.ts | 6 +++-- libs/optimizer/src/lib/optimizer.ts | 8 ++++--- .../src/lib/utils/create-segments.ts | 2 +- libs/optimizer/src/lib/utils/merge-tracks.ts | 2 +- libs/vaadin-dom/src/lib/Binder.ts | 6 +++-- libs/vaadin-dom/src/lib/Field.ts | 9 +++++--- libs/vaadin-nodom/src/lib/BinderNode.ts | 5 +++-- libs/vaadin-nodom/src/lib/NoDomBinder.ts | 12 +++++----- libs/vaadin-nodom/src/lib/Validation.ts | 3 ++- 134 files changed, 483 insertions(+), 298 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 67e3c191..b9c2deb0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -19,7 +19,8 @@ ] } ], - "require-node-import-prefix/no-empty-import-prefix": "error" + "require-node-import-prefix/no-empty-import-prefix": "error", + "@typescript-eslint/consistent-type-imports": "error" } }, { diff --git a/apps/airspaces/src/app/create-geojson.ts b/apps/airspaces/src/app/create-geojson.ts index c129d455..1db41f64 100755 --- a/apps/airspaces/src/app/create-geojson.ts +++ b/apps/airspaces/src/app/create-geojson.ts @@ -6,7 +6,7 @@ import { readFileSync, writeFileSync } from 'node:fs'; import { join, resolve } from 'node:path'; import * as oaip from './parser/openaip'; import * as oair from './parser/openair'; -import { Airspace } from './parser/parser'; +import type { Airspace } from './parser/parser'; const GeoJSON = require('geojson'); // eslint-disable-line @typescript-eslint/no-var-requires // Filter out airspaces above: diff --git a/apps/airspaces/src/app/parser/openaip.ts b/apps/airspaces/src/app/parser/openaip.ts index 75afd9a8..bbee92c4 100644 --- a/apps/airspaces/src/app/parser/openaip.ts +++ b/apps/airspaces/src/app/parser/openaip.ts @@ -1,5 +1,6 @@ import { Activity, Class, Type } from '@flyxc/common'; -import { Airspace, METER_PER_FEET, roundCoords } from './parser'; +import type { Airspace} from './parser'; +import { METER_PER_FEET, roundCoords } from './parser'; enum Unit { Meter = 0, diff --git a/apps/airspaces/src/app/parser/openair.ts b/apps/airspaces/src/app/parser/openair.ts index 42af2a1c..469c06c7 100644 --- a/apps/airspaces/src/app/parser/openair.ts +++ b/apps/airspaces/src/app/parser/openair.ts @@ -4,7 +4,8 @@ import { Activity, Class, Type, decodeClass } from '@flyxc/common'; import { computeDestinationPoint, getDistance, getGreatCircleBearing, sexagesimalToDecimal } from 'geolib'; -import { Airspace, METER_PER_FEET, roundCoords } from './parser'; +import type { Airspace} from './parser'; +import { METER_PER_FEET, roundCoords } from './parser'; const enum Direction { Clockwise = 1, diff --git a/apps/airspaces/src/app/parser/parser.ts b/apps/airspaces/src/app/parser/parser.ts index 8925d7a6..81982e6f 100644 --- a/apps/airspaces/src/app/parser/parser.ts +++ b/apps/airspaces/src/app/parser/parser.ts @@ -1,4 +1,5 @@ -import { AirspaceTyped, round } from '@flyxc/common'; +import type { AirspaceTyped} from '@flyxc/common'; +import { round } from '@flyxc/common'; export interface Airspace extends AirspaceTyped { polygon: [number, number][][]; diff --git a/apps/airspaces/src/app/upload-tiles-diff.ts b/apps/airspaces/src/app/upload-tiles-diff.ts index c5219d35..6f221dcd 100644 --- a/apps/airspaces/src/app/upload-tiles-diff.ts +++ b/apps/airspaces/src/app/upload-tiles-diff.ts @@ -1,7 +1,8 @@ // Unzip tiles to Google Cloud Storage. import { parallelTasksWithTimeout } from '@flyxc/common'; -import { Bucket, Storage } from '@google-cloud/storage'; +import type { Bucket} from '@google-cloud/storage'; +import { Storage } from '@google-cloud/storage'; import { program } from 'commander'; import { existsSync, readFileSync } from 'node:fs'; import path, { join, resolve } from 'node:path'; diff --git a/apps/fetcher/src/app/elevation/arcgis.ts b/apps/fetcher/src/app/elevation/arcgis.ts index 816c21ad..91b5f70e 100644 --- a/apps/fetcher/src/app/elevation/arcgis.ts +++ b/apps/fetcher/src/app/elevation/arcgis.ts @@ -1,4 +1,4 @@ -import { LatLon } from '@flyxc/common'; +import type { LatLon } from '@flyxc/common'; // URL of the elevation service. // diff --git a/apps/fetcher/src/app/elevation/elevation.ts b/apps/fetcher/src/app/elevation/elevation.ts index d0dc86fc..0d89cd79 100644 --- a/apps/fetcher/src/app/elevation/elevation.ts +++ b/apps/fetcher/src/app/elevation/elevation.ts @@ -2,7 +2,8 @@ // // We mostly care about the AGL of the last fix. -import { fetchResponse, formatReqError, LatLon, protos } from '@flyxc/common'; +import type { LatLon, protos } from '@flyxc/common'; +import { fetchResponse, formatReqError } from '@flyxc/common'; import { getElevationUrl, parseElevationResponse } from './arcgis'; export interface ElevationUpdates { diff --git a/apps/fetcher/src/app/redis.ts b/apps/fetcher/src/app/redis.ts index 34492574..d2dadbf4 100644 --- a/apps/fetcher/src/app/redis.ts +++ b/apps/fetcher/src/app/redis.ts @@ -1,13 +1,14 @@ import { Keys, protos, trackerNames } from '@flyxc/common'; import { pushListCap } from '@flyxc/common-node'; -import { Datastore } from '@google-cloud/datastore'; -import { ChainableCommander, Redis } from 'ioredis'; +import type { Datastore } from '@google-cloud/datastore'; +import type { ChainableCommander, Redis } from 'ioredis'; import * as nos from 'node-os-utils'; import * as zlib from 'node:zlib'; -import { ElevationUpdates } from './elevation/elevation'; +import type { ElevationUpdates } from './elevation/elevation'; import { exportToStorage } from './state/serialize'; import { BUCKET_NAME, EXPORT_FILE_SEC, PERIODIC_STATE_PATH } from './state/state'; -import { SyncStatus, syncFromDatastore } from './state/sync'; +import type { SyncStatus} from './state/sync'; +import { syncFromDatastore } from './state/sync'; // Logs for syncs. export function addSyncLogs(pipeline: ChainableCommander, status: SyncStatus, timeSec: number) { diff --git a/apps/fetcher/src/app/state/serialize.ts b/apps/fetcher/src/app/state/serialize.ts index 7b3a9c22..58ce9613 100644 --- a/apps/fetcher/src/app/state/serialize.ts +++ b/apps/fetcher/src/app/state/serialize.ts @@ -1,5 +1,6 @@ import { protos } from '@flyxc/common'; -import { File, Storage } from '@google-cloud/storage'; +import type { File} from '@google-cloud/storage'; +import { Storage } from '@google-cloud/storage'; import { isBefore, lightFormat, parse, sub } from 'date-fns'; import * as zlib from 'node:zlib'; diff --git a/apps/fetcher/src/app/state/state.ts b/apps/fetcher/src/app/state/state.ts index db902934..5b162481 100644 --- a/apps/fetcher/src/app/state/state.ts +++ b/apps/fetcher/src/app/state/state.ts @@ -1,4 +1,4 @@ -import { protos } from '@flyxc/common'; +import type { protos } from '@flyxc/common'; import { environment } from '../../environments/environment.prod'; import { importFromStorage } from './serialize'; diff --git a/apps/fetcher/src/app/state/sync.test.ts b/apps/fetcher/src/app/state/sync.test.ts index 1da3e992..c4353ba0 100644 --- a/apps/fetcher/src/app/state/sync.test.ts +++ b/apps/fetcher/src/app/state/sync.test.ts @@ -1,5 +1,7 @@ -import { LiveTrackEntity, protos, TrackerEntity, TrackerNames } from '@flyxc/common'; -import { Datastore, Key } from '@google-cloud/datastore'; +import type { LiveTrackEntity, TrackerEntity, TrackerNames } from '@flyxc/common'; +import { protos } from '@flyxc/common'; +import type { Key } from '@google-cloud/datastore'; +import { Datastore } from '@google-cloud/datastore'; import { createInitState } from './state'; import { syncLiveTrack } from './sync'; diff --git a/apps/fetcher/src/app/state/sync.ts b/apps/fetcher/src/app/state/sync.ts index 1548d0fb..40be4969 100644 --- a/apps/fetcher/src/app/state/sync.ts +++ b/apps/fetcher/src/app/state/sync.ts @@ -1,7 +1,8 @@ +import type { + LiveTrackEntity, + TrackerNames} from '@flyxc/common'; import { LIVE_REFRESH_SEC, - LiveTrackEntity, - TrackerNames, protos, trackerNames, trackerValidators, @@ -10,7 +11,7 @@ import { } from '@flyxc/common'; import { LIVE_TRACK_TABLE } from '@flyxc/common-node'; import { Datastore } from '@google-cloud/datastore'; -import { RunQueryResponse } from '@google-cloud/datastore/build/src/query'; +import type { RunQueryResponse } from '@google-cloud/datastore/build/src/query'; import { FULL_SYNC_SEC, PARTIAL_SYNC_SEC } from './state'; const BATCH_SIZE = 50; diff --git a/apps/fetcher/src/app/trackers/flymaster.ts b/apps/fetcher/src/app/trackers/flymaster.ts index 3412490d..e0f76c48 100644 --- a/apps/fetcher/src/app/trackers/flymaster.ts +++ b/apps/fetcher/src/app/trackers/flymaster.ts @@ -2,19 +2,22 @@ // // https://lt.flymaster.net/wlb/? +import type { + protos, + TrackerNames} from '@flyxc/common'; import { fetchResponse, formatReqError, LIVE_MINIMAL_INTERVAL_SEC, - protos, removeBeforeFromLiveTrack, simplifyLiveTrack, - TrackerNames, validateFlymasterAccount, SecretKeys, } from '@flyxc/common'; -import { LivePoint, makeLiveTrack } from './live-track'; -import { TrackerFetcher, TrackerUpdates } from './tracker'; +import type { LivePoint} from './live-track'; +import { makeLiveTrack } from './live-track'; +import type { TrackerUpdates } from './tracker'; +import { TrackerFetcher } from './tracker'; // Latency before a fix is available (usually ~4min). const FLYMASTER_LATENCY_SEC = 5 * 60; diff --git a/apps/fetcher/src/app/trackers/flyme.ts b/apps/fetcher/src/app/trackers/flyme.ts index 7fc55d60..213d33f5 100644 --- a/apps/fetcher/src/app/trackers/flyme.ts +++ b/apps/fetcher/src/app/trackers/flyme.ts @@ -2,9 +2,12 @@ // // http://xcglobe.com/flyme/ -import { fetchResponse, formatReqError, protos, SecretKeys, TrackerNames, validateFlymeAccount } from '@flyxc/common'; -import { LivePoint, makeLiveTrack } from './live-track'; -import { TrackerFetcher, TrackerUpdates } from './tracker'; +import type { protos, TrackerNames} from '@flyxc/common'; +import { fetchResponse, formatReqError, SecretKeys, validateFlymeAccount } from '@flyxc/common'; +import type { LivePoint} from './live-track'; +import { makeLiveTrack } from './live-track'; +import type { TrackerUpdates } from './tracker'; +import { TrackerFetcher } from './tracker'; export class FlymeFetcher extends TrackerFetcher { protected getTrackerName(): TrackerNames { diff --git a/apps/fetcher/src/app/trackers/inreach.ts b/apps/fetcher/src/app/trackers/inreach.ts index 83a24f52..21e17490 100644 --- a/apps/fetcher/src/app/trackers/inreach.ts +++ b/apps/fetcher/src/app/trackers/inreach.ts @@ -2,6 +2,8 @@ // // See https://support.garmin.com/en-US/?faq=tdlDCyo1fJ5UxjUbA9rMY8. +import type { + TrackerNames} from '@flyxc/common'; import { fetchResponse, formatReqError, @@ -12,14 +14,15 @@ import { protos, SecretKeys, simplifyLiveTrack, - TrackerNames, validateInreachAccount, } from '@flyxc/common'; import { pushListCap } from '@flyxc/common-node'; import { DOMParser } from '@xmldom/xmldom'; -import { LivePoint, makeLiveTrack } from './live-track'; +import type { LivePoint} from './live-track'; +import { makeLiveTrack } from './live-track'; import { Proxies } from './proxies'; -import { TrackerFetcher, TrackerUpdates } from './tracker'; +import type { TrackerUpdates } from './tracker'; +import { TrackerFetcher } from './tracker'; // Local state let useProxyUntilS = 0; diff --git a/apps/fetcher/src/app/trackers/live-track.test.ts b/apps/fetcher/src/app/trackers/live-track.test.ts index 979b10c4..efcc3c82 100644 --- a/apps/fetcher/src/app/trackers/live-track.test.ts +++ b/apps/fetcher/src/app/trackers/live-track.test.ts @@ -1,6 +1,7 @@ import { getTrackerName, isEmergencyFix, isLowBatFix, isValidFix, LiveTrackFlag, trackerIdByName } from '@flyxc/common'; import { computeDestinationPoint } from 'geolib'; -import { LivePoint, makeLiveTrack } from './live-track'; +import type { LivePoint} from './live-track'; +import { makeLiveTrack } from './live-track'; describe('makeLiveTrack', () => { it('should order the points in chronological order', () => { diff --git a/apps/fetcher/src/app/trackers/live-track.ts b/apps/fetcher/src/app/trackers/live-track.ts index a4671b52..fb55041d 100644 --- a/apps/fetcher/src/app/trackers/live-track.ts +++ b/apps/fetcher/src/app/trackers/live-track.ts @@ -1,4 +1,5 @@ -import { getTrackerFlags as getLiveTrackFlags, protos, round, TrackerNames, UfoFleetNames } from '@flyxc/common'; +import type { TrackerNames, UfoFleetNames } from '@flyxc/common'; +import { getTrackerFlags as getLiveTrackFlags, protos, round } from '@flyxc/common'; import { getDistance } from 'geolib'; export interface LivePoint { diff --git a/apps/fetcher/src/app/trackers/ogn-client.ts b/apps/fetcher/src/app/trackers/ogn-client.ts index 278a53cb..51b8dbec 100644 --- a/apps/fetcher/src/app/trackers/ogn-client.ts +++ b/apps/fetcher/src/app/trackers/ogn-client.ts @@ -1,8 +1,10 @@ // Client for the OGN APRS server -import { AprsPosition, parseAprsPosition } from '@flyxc/common'; +import type { AprsPosition} from '@flyxc/common'; +import { parseAprsPosition } from '@flyxc/common'; import { Socket } from 'node:net'; -import readline, { Interface } from 'node:readline'; +import type { Interface } from 'node:readline'; +import readline from 'node:readline'; const VERSION = '1.0'; const OGN_FAST_ID_REGEXP = /\bid[0-9a-z]{2}(?[0-9a-z]{6})\b/i; diff --git a/apps/fetcher/src/app/trackers/ogn-push.ts b/apps/fetcher/src/app/trackers/ogn-push.ts index 2e4af919..dd8f719b 100644 --- a/apps/fetcher/src/app/trackers/ogn-push.ts +++ b/apps/fetcher/src/app/trackers/ogn-push.ts @@ -1,6 +1,7 @@ -import { AprsPosition, findIndexes, generateAprsPosition, getFixSpeed, getTrackerName, protos } from '@flyxc/common'; +import type { AprsPosition, protos } from '@flyxc/common'; +import { findIndexes, generateAprsPosition, getFixSpeed, getTrackerName } from '@flyxc/common'; import { getRhumbLineBearing } from 'geolib'; -import { OgnClient } from './ogn-client'; +import type { OgnClient } from './ogn-client'; // Don't push obsolete fixes. const RECENT_FIX_AGE_SEC = 10 * 60; diff --git a/apps/fetcher/src/app/trackers/ogn.ts b/apps/fetcher/src/app/trackers/ogn.ts index b2677447..695aa74e 100644 --- a/apps/fetcher/src/app/trackers/ogn.ts +++ b/apps/fetcher/src/app/trackers/ogn.ts @@ -2,12 +2,15 @@ // // See http://wiki.glidernet.org/. -import { protos, TrackerNames, validateOgnAccount } from '@flyxc/common'; -import { ChainableCommander } from 'ioredis'; -import { LivePoint, makeLiveTrack } from './live-track'; -import { OgnClient } from './ogn-client'; +import type { protos, TrackerNames} from '@flyxc/common'; +import { validateOgnAccount } from '@flyxc/common'; +import type { ChainableCommander } from 'ioredis'; +import type { LivePoint} from './live-track'; +import { makeLiveTrack } from './live-track'; +import type { OgnClient } from './ogn-client'; import { OgnPusher } from './ogn-push'; -import { TrackerFetcher, TrackerUpdates } from './tracker'; +import type { TrackerUpdates } from './tracker'; +import { TrackerFetcher } from './tracker'; // Push positions to OGN. let ognPusher: OgnPusher | undefined; diff --git a/apps/fetcher/src/app/trackers/refresh.ts b/apps/fetcher/src/app/trackers/refresh.ts index def740f9..d989dfbb 100644 --- a/apps/fetcher/src/app/trackers/refresh.ts +++ b/apps/fetcher/src/app/trackers/refresh.ts @@ -1,3 +1,5 @@ +import type { + protos} from '@flyxc/common'; import { Keys, LIVE_AGE_OLD_SEC, @@ -7,13 +9,12 @@ import { LIVE_TRACKER_RETENTION_SEC, SecretKeys, mergeLiveTracks, - protos, removeBeforeFromLiveTrack, simplifyLiveTrack, } from '@flyxc/common'; import { pushListCap } from '@flyxc/common-node'; -import { Datastore } from '@google-cloud/datastore'; -import { ChainableCommander, Redis } from 'ioredis'; +import type { Datastore } from '@google-cloud/datastore'; +import type { ChainableCommander, Redis } from 'ioredis'; import { patchLastFixAGL } from '../elevation/elevation'; import { addElevationLogs } from '../redis'; import { FlymasterFetcher } from './flymaster'; @@ -23,7 +24,7 @@ import { OgnFetcher } from './ogn'; import { OGN_HOST, OGN_PORT, OgnClient } from './ogn-client'; import { SkylinesFetcher } from './skylines'; import { SpotFetcher } from './spot'; -import { TrackerUpdates } from './tracker'; +import type { TrackerUpdates } from './tracker'; import { XcontestFetcher } from './xcontest'; import { ZoleoFetcher } from './zoleo'; diff --git a/apps/fetcher/src/app/trackers/skylines.ts b/apps/fetcher/src/app/trackers/skylines.ts index 79be5dcb..f67dcf0f 100644 --- a/apps/fetcher/src/app/trackers/skylines.ts +++ b/apps/fetcher/src/app/trackers/skylines.ts @@ -2,19 +2,22 @@ // // See https://github.com/skylines-project/skylines. +import type { + protos, + TrackerNames} from '@flyxc/common'; import { decodeDeltas, fetchResponse, formatReqError, LIVE_MINIMAL_INTERVAL_SEC, - protos, removeBeforeFromLiveTrack, simplifyLiveTrack, - TrackerNames, validateSkylinesAccount, } from '@flyxc/common'; -import { LivePoint, makeLiveTrack } from './live-track'; -import { TrackerFetcher, TrackerUpdates } from './tracker'; +import type { LivePoint} from './live-track'; +import { makeLiveTrack } from './live-track'; +import type { TrackerUpdates } from './tracker'; +import { TrackerFetcher } from './tracker'; const SECONDS_IN_DAY = 60 * 60 * 24; diff --git a/apps/fetcher/src/app/trackers/spot.test.ts b/apps/fetcher/src/app/trackers/spot.test.ts index ca68bf86..97ab967e 100644 --- a/apps/fetcher/src/app/trackers/spot.test.ts +++ b/apps/fetcher/src/app/trackers/spot.test.ts @@ -2,7 +2,7 @@ const spot2Feed = require('./fixtures/spot2.txt'); const spot3Feed = require('./fixtures/spot3.txt'); -import { LivePoint } from './live-track'; +import type { LivePoint } from './live-track'; import { parse } from './spot'; describe('Parse JSON feed', () => { diff --git a/apps/fetcher/src/app/trackers/spot.ts b/apps/fetcher/src/app/trackers/spot.ts index 18244eba..07e650bd 100644 --- a/apps/fetcher/src/app/trackers/spot.ts +++ b/apps/fetcher/src/app/trackers/spot.ts @@ -2,17 +2,20 @@ // // See https://www.findmespot.com/en-us/support/spot-trace/get-help/general/spot-api-support. +import type { + protos, + TrackerNames} from '@flyxc/common'; import { fetchResponse, formatReqError, LIVE_MINIMAL_INTERVAL_SEC, - protos, simplifyLiveTrack, - TrackerNames, validateSpotAccount, } from '@flyxc/common'; -import { LivePoint, makeLiveTrack } from './live-track'; -import { TrackerFetcher, TrackerUpdates } from './tracker'; +import type { LivePoint} from './live-track'; +import { makeLiveTrack } from './live-track'; +import type { TrackerUpdates } from './tracker'; +import { TrackerFetcher } from './tracker'; export class SpotFetcher extends TrackerFetcher { protected getTrackerName(): TrackerNames { diff --git a/apps/fetcher/src/app/trackers/tracker.ts b/apps/fetcher/src/app/trackers/tracker.ts index dc0b6ed9..928f415b 100644 --- a/apps/fetcher/src/app/trackers/tracker.ts +++ b/apps/fetcher/src/app/trackers/tracker.ts @@ -1,7 +1,8 @@ // Base class for fetching tracker updates. -import { LIVE_REFRESH_SEC, LIVE_TRACKER_RETENTION_SEC, protos, TrackerNames } from '@flyxc/common'; -import { ChainableCommander } from 'ioredis'; +import type { protos, TrackerNames } from '@flyxc/common'; +import { LIVE_REFRESH_SEC, LIVE_TRACKER_RETENTION_SEC } from '@flyxc/common'; +import type { ChainableCommander } from 'ioredis'; // Updates for a tick of a tracker type (InReach, Spot, ...). export interface TrackerUpdates { diff --git a/apps/fetcher/src/app/trackers/xcontest.test.ts b/apps/fetcher/src/app/trackers/xcontest.test.ts index c07989b9..d5d47d9d 100644 --- a/apps/fetcher/src/app/trackers/xcontest.test.ts +++ b/apps/fetcher/src/app/trackers/xcontest.test.ts @@ -2,7 +2,8 @@ const xcontestUsers = require('./fixtures/xcontest-live-users.json'); const xcontestTrack = require('./fixtures/xcontest-live-track.json'); -import { XContestFlight, parseLiveTrack, parseLiveUsers } from './xcontest'; +import type { XContestFlight} from './xcontest'; +import { parseLiveTrack, parseLiveUsers } from './xcontest'; describe('Parse XContest json', () => { test('it should parse users', () => { diff --git a/apps/fetcher/src/app/trackers/xcontest.ts b/apps/fetcher/src/app/trackers/xcontest.ts index 6ba0643c..1eee811d 100644 --- a/apps/fetcher/src/app/trackers/xcontest.ts +++ b/apps/fetcher/src/app/trackers/xcontest.ts @@ -2,18 +2,21 @@ // // https://live.xcontest.org/ +import type { + protos, + TrackerNames} from '@flyxc/common'; import { fetchResponse, formatReqError, LIVE_TRACKER_RETENTION_SEC, parallelTasksWithTimeout, - protos, SecretKeys, - TrackerNames, validateXContestAccount, } from '@flyxc/common'; -import { LivePoint, makeLiveTrack } from './live-track'; -import { TrackerFetcher, TrackerUpdates } from './tracker'; +import type { LivePoint} from './live-track'; +import { makeLiveTrack } from './live-track'; +import type { TrackerUpdates } from './tracker'; +import { TrackerFetcher } from './tracker'; // duration to fetch const FETCH_MS = 4 * 60 * 1000; diff --git a/apps/fetcher/src/app/trackers/zoleo.test.ts b/apps/fetcher/src/app/trackers/zoleo.test.ts index 48d20b45..648d5311 100644 --- a/apps/fetcher/src/app/trackers/zoleo.test.ts +++ b/apps/fetcher/src/app/trackers/zoleo.test.ts @@ -1,4 +1,4 @@ -import { ZoleoMessage } from '@flyxc/common-node'; +import type { ZoleoMessage } from '@flyxc/common-node'; import { parse } from './zoleo'; describe('parse', () => { diff --git a/apps/fetcher/src/app/trackers/zoleo.ts b/apps/fetcher/src/app/trackers/zoleo.ts index 26817498..94a58ff1 100644 --- a/apps/fetcher/src/app/trackers/zoleo.ts +++ b/apps/fetcher/src/app/trackers/zoleo.ts @@ -1,9 +1,13 @@ -import { Keys, TrackerNames, protos, validateZoleoAccount } from '@flyxc/common'; -import { LIVE_TRACK_TABLE, ZoleoMessage } from '@flyxc/common-node'; +import type { TrackerNames, protos} from '@flyxc/common'; +import { Keys, validateZoleoAccount } from '@flyxc/common'; +import type { ZoleoMessage } from '@flyxc/common-node'; +import { LIVE_TRACK_TABLE } from '@flyxc/common-node'; import { Datastore } from '@google-cloud/datastore'; -import { ChainableCommander, Redis } from 'ioredis'; -import { LivePoint, makeLiveTrack } from './live-track'; -import { TrackerFetcher, TrackerUpdates } from './tracker'; +import type { ChainableCommander, Redis } from 'ioredis'; +import type { LivePoint} from './live-track'; +import { makeLiveTrack } from './live-track'; +import type { TrackerUpdates } from './tracker'; +import { TrackerFetcher } from './tracker'; export class ZoleoFetcher extends TrackerFetcher { constructor( diff --git a/apps/fetcher/src/app/ufos/aviant.ts b/apps/fetcher/src/app/ufos/aviant.ts index 63827f68..64a4cdb0 100644 --- a/apps/fetcher/src/app/ufos/aviant.ts +++ b/apps/fetcher/src/app/ufos/aviant.ts @@ -1,8 +1,11 @@ // https://www.aviant.no/ -import { fetchResponse, formatReqError, SecretKeys, UfoFleetNames } from '@flyxc/common'; -import { LivePoint, makeLiveTrack } from '../trackers/live-track'; -import { UfoFleetFetcher, UfoFleetUpdates } from './ufo'; +import type { UfoFleetNames } from '@flyxc/common'; +import { fetchResponse, formatReqError, SecretKeys } from '@flyxc/common'; +import type { LivePoint} from '../trackers/live-track'; +import { makeLiveTrack } from '../trackers/live-track'; +import type { UfoFleetUpdates } from './ufo'; +import { UfoFleetFetcher } from './ufo'; export class AviantFetcher extends UfoFleetFetcher { protected getFleetName(): UfoFleetNames { diff --git a/apps/fetcher/src/app/ufos/refresh.ts b/apps/fetcher/src/app/ufos/refresh.ts index 681cc03b..51ddd50f 100644 --- a/apps/fetcher/src/app/ufos/refresh.ts +++ b/apps/fetcher/src/app/ufos/refresh.ts @@ -1,17 +1,18 @@ +import type { + protos} from '@flyxc/common'; import { Keys, LIVE_FETCH_TIMEOUT_SEC, LIVE_MINIMAL_INTERVAL_SEC, LIVE_UFO_RETENTION_SEC, mergeLiveTracks, - protos, removeBeforeFromLiveTrack, simplifyLiveTrack, } from '@flyxc/common'; import { pushListCap } from '@flyxc/common-node'; -import { ChainableCommander } from 'ioredis'; +import type { ChainableCommander } from 'ioredis'; import { AviantFetcher } from './aviant'; -import { UfoFleetUpdates } from './ufo'; +import type { UfoFleetUpdates } from './ufo'; export async function resfreshUfoFleets(pipeline: ChainableCommander, state: protos.FetcherState) { const fetchers = [new AviantFetcher(state, pipeline)]; diff --git a/apps/fetcher/src/app/ufos/ufo.ts b/apps/fetcher/src/app/ufos/ufo.ts index b0c04a8d..c1655dff 100644 --- a/apps/fetcher/src/app/ufos/ufo.ts +++ b/apps/fetcher/src/app/ufos/ufo.ts @@ -1,5 +1,6 @@ -import { LIVE_REFRESH_SEC, protos, UfoFleetNames } from '@flyxc/common'; -import { ChainableCommander } from 'ioredis'; +import type { UfoFleetNames } from '@flyxc/common'; +import { LIVE_REFRESH_SEC, protos } from '@flyxc/common'; +import type { ChainableCommander } from 'ioredis'; // Updates for a tick of a tracker type (InReach, Spot, ...). export interface UfoFleetUpdates { diff --git a/apps/fetcher/src/fetcher.ts b/apps/fetcher/src/fetcher.ts index cb7b8f6c..44689ebc 100644 --- a/apps/fetcher/src/fetcher.ts +++ b/apps/fetcher/src/fetcher.ts @@ -10,9 +10,9 @@ import { removeDeviceFromLiveTrack, } from '@flyxc/common'; import { getDatastore, getRedisClient, pushListCap } from '@flyxc/common-node'; -import { Datastore } from '@google-cloud/datastore'; +import type { Datastore } from '@google-cloud/datastore'; import { program } from 'commander'; -import { ChainableCommander } from 'ioredis'; +import type { ChainableCommander } from 'ioredis'; import process from 'node:process'; import { addExportLogs, addHostInfo, addStateLogs, addSyncLogs, HandleCommand } from './app/redis'; import { createStateArchive, exportToStorage } from './app/state/serialize'; diff --git a/apps/fxc-front/src/app/components/2d/airspace-element.ts b/apps/fxc-front/src/app/components/2d/airspace-element.ts index 048ce38c..f3a71a84 100644 --- a/apps/fxc-front/src/app/components/2d/airspace-element.ts +++ b/apps/fxc-front/src/app/components/2d/airspace-element.ts @@ -1,11 +1,13 @@ import * as common from '@flyxc/common'; -import { LitElement, PropertyValues } from 'lit'; +import type { PropertyValues } from 'lit'; +import { LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; import { AspMapType, AspZoomMapType, getAirspaceList } from '../../logic/airspaces'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; @customElement('airspace-element') export class AirspaceElement extends connect(store)(LitElement) { diff --git a/apps/fxc-front/src/app/components/2d/controls-element.ts b/apps/fxc-front/src/app/components/2d/controls-element.ts index e0d23187..4cfcb8d7 100644 --- a/apps/fxc-front/src/app/components/2d/controls-element.ts +++ b/apps/fxc-front/src/app/components/2d/controls-element.ts @@ -6,14 +6,16 @@ import './path-element'; import './skyways-element'; import './tracking-element'; -import * as common from '@flyxc/common'; -import { css, CSSResult, html, LitElement, TemplateResult } from 'lit'; +import type * as common from '@flyxc/common'; +import type { CSSResult, TemplateResult } from 'lit'; +import { css, html, LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; import { connect } from 'pwa-helpers'; -import * as units from '../../logic/units'; +import type * as units from '../../logic/units'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; @customElement('controls-element') export class ControlsElement extends connect(store)(LitElement) { diff --git a/apps/fxc-front/src/app/components/2d/line-element.ts b/apps/fxc-front/src/app/components/2d/line-element.ts index 88e27c4e..8ca084a0 100644 --- a/apps/fxc-front/src/app/components/2d/line-element.ts +++ b/apps/fxc-front/src/app/components/2d/line-element.ts @@ -1,10 +1,12 @@ -import * as common from '@flyxc/common'; -import { LitElement, PropertyValues } from 'lit'; +import type * as common from '@flyxc/common'; +import type { PropertyValues } from 'lit'; +import { LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; const INACTIVE_OPACITY = 0.5; diff --git a/apps/fxc-front/src/app/components/2d/map-element.ts b/apps/fxc-front/src/app/components/2d/map-element.ts index 20486e19..40ce4a29 100644 --- a/apps/fxc-front/src/app/components/2d/map-element.ts +++ b/apps/fxc-front/src/app/components/2d/map-element.ts @@ -1,10 +1,12 @@ -import { findClosestFix, LatLon, LatLonAlt, pixelCoordinates, RuntimeTrack } from '@flyxc/common'; +import type { LatLon, LatLonAlt, RuntimeTrack } from '@flyxc/common'; +import { findClosestFix, pixelCoordinates } from '@flyxc/common'; import { Loader } from '@googlemaps/js-api-loader'; -import { html, LitElement, PropertyValues, svg, TemplateResult } from 'lit'; +import type { PropertyValues, TemplateResult } from 'lit'; +import { html, LitElement, svg } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; import { when } from 'lit/directives/when.js'; -import { UnsubscribeHandle } from 'micro-typed-events'; +import type { UnsubscribeHandle } from 'micro-typed-events'; import { connect } from 'pwa-helpers'; import simplify from 'simplify-path'; import { getApiKeyAndHost } from '../../apikey'; @@ -13,7 +15,8 @@ import { setApiLoading, setTimeSec } from '../../redux/app-slice'; import { setCurrentLocation, setCurrentZoom } from '../../redux/location-slice'; import { setIsFreeDrawing, setRoute } from '../../redux/planner-slice'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; import { setCurrentTrackId } from '../../redux/track-slice'; import { ControlsElement } from './controls-element'; import { LineElement } from './line-element'; diff --git a/apps/fxc-front/src/app/components/2d/marker-element.ts b/apps/fxc-front/src/app/components/2d/marker-element.ts index b901fa31..70f2e9e8 100644 --- a/apps/fxc-front/src/app/components/2d/marker-element.ts +++ b/apps/fxc-front/src/app/components/2d/marker-element.ts @@ -1,10 +1,12 @@ -import * as common from '@flyxc/common'; -import { LitElement, PropertyValues, html, nothing } from 'lit'; +import type * as common from '@flyxc/common'; +import type { PropertyValues} from 'lit'; +import { LitElement, html, nothing } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; import * as units from '../../logic/units'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; import { setCurrentTrackId } from '../../redux/track-slice'; import './adv-marker-element'; diff --git a/apps/fxc-front/src/app/components/2d/path-element.ts b/apps/fxc-front/src/app/components/2d/path-element.ts index deeeb9f2..09c6d4c6 100644 --- a/apps/fxc-front/src/app/components/2d/path-element.ts +++ b/apps/fxc-front/src/app/components/2d/path-element.ts @@ -1,8 +1,9 @@ import '../ui/share-modal'; import '../ui/waypoint-modal'; -import { LatLon } from '@flyxc/common'; -import { LitElement, PropertyValues } from 'lit'; +import type { LatLon } from '@flyxc/common'; +import type { PropertyValues } from 'lit'; +import { LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; @@ -15,8 +16,9 @@ import { getCurrentUrl, pushCurrentState } from '../../logic/history'; import { drawRoute } from '../../logic/messages'; import { Score } from '../../logic/score/scorer'; import { setDistance, setEnabled, setRoute, setScore } from '../../redux/planner-slice'; -import { RootState, store } from '../../redux/store'; -import { PlannerElement } from './planner-element'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; +import type { PlannerElement } from './planner-element'; import { CircuitType, getOptimizer } from '@flyxc/optimizer'; import { getScoringRuleName } from '../../logic/score/league/leagues'; import type { LeagueCode } from '../../logic/score/league/leagues'; diff --git a/apps/fxc-front/src/app/components/2d/planner-element.ts b/apps/fxc-front/src/app/components/2d/planner-element.ts index 65ca3958..693fec8b 100644 --- a/apps/fxc-front/src/app/components/2d/planner-element.ts +++ b/apps/fxc-front/src/app/components/2d/planner-element.ts @@ -1,13 +1,15 @@ -import { css, CSSResult, html, LitElement, TemplateResult } from 'lit'; +import type { CSSResult, TemplateResult } from 'lit'; +import { css, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { when } from 'lit/directives/when.js'; import { connect } from 'pwa-helpers'; -import { Score } from '../../logic/score/scorer'; +import type { Score } from '../../logic/score/scorer'; import * as units from '../../logic/units'; import { decrementSpeed, incrementSpeed, setSpeed } from '../../redux/planner-slice'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; const ICON_MINUS = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJAQMAAADaX5RTAAAABlBMVEX///9xe4e/5menAAAAE0lEQVQImWP438DQAEP7kNj/GwCK4wo9HA2mvgAAAABJRU5ErkJggg=='; diff --git a/apps/fxc-front/src/app/components/2d/skyways-element.ts b/apps/fxc-front/src/app/components/2d/skyways-element.ts index 4108731d..f4fef9b6 100644 --- a/apps/fxc-front/src/app/components/2d/skyways-element.ts +++ b/apps/fxc-front/src/app/components/2d/skyways-element.ts @@ -1,9 +1,11 @@ -import { html, LitElement, PropertyValues } from 'lit'; +import type { PropertyValues } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { TemplateResult } from 'lit/html.js'; +import type { TemplateResult } from 'lit/html.js'; import { connect } from 'pwa-helpers'; import * as skyways from '../../redux/skyways-slice'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; import { GMAP_MAX_ZOOM_LEVEL } from './map-element'; import { WMTSInterpolatingOverlayElement } from './wmts-overlay'; diff --git a/apps/fxc-front/src/app/components/2d/tracking-element.ts b/apps/fxc-front/src/app/components/2d/tracking-element.ts index 147f1193..ed28c200 100644 --- a/apps/fxc-front/src/app/components/2d/tracking-element.ts +++ b/apps/fxc-front/src/app/components/2d/tracking-element.ts @@ -1,12 +1,16 @@ -import { LitElement, PropertyValues } from 'lit'; +import type { PropertyValues } from 'lit'; +import { LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; -import { FixType, LiveLineProperties, LivePointProperties } from '../../logic/live-track'; +import type { LiveLineProperties, LivePointProperties } from '../../logic/live-track'; +import { FixType } from '../../logic/live-track'; import { popupContent } from '../../logic/live-track-popup'; -import { Units, formatDurationMin, formatUnit } from '../../logic/units'; +import type { Units} from '../../logic/units'; +import { formatDurationMin, formatUnit } from '../../logic/units'; import { setCurrentLiveId } from '../../redux/live-track-slice'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; import { getUniqueContrastColor } from '../../styles/track'; // Anchors and label origins for markers. diff --git a/apps/fxc-front/src/app/components/3d/airspace3d-element.ts b/apps/fxc-front/src/app/components/3d/airspace3d-element.ts index beb9eb00..04b07099 100644 --- a/apps/fxc-front/src/app/components/3d/airspace3d-element.ts +++ b/apps/fxc-front/src/app/components/3d/airspace3d-element.ts @@ -3,9 +3,11 @@ import { customElement, property, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; import VectorTileLayer from '@arcgis/core/layers/VectorTileLayer'; -import Map from '@arcgis/core/Map'; +import type Map from '@arcgis/core/Map'; -import SceneView from '@arcgis/core/views/SceneView'; +import type SceneView from '@arcgis/core/views/SceneView'; +import type { + LatLon} from '@flyxc/common'; import { ASP_COLOR_DANGER, ASP_COLOR_OTHER, @@ -13,12 +15,12 @@ import { ASP_COLOR_RESTRICTED, Class, getAirspaceTilesUrlTemplate, - LatLon, MAX_AIRSPACE_TILE_ZOOM, Type, } from '@flyxc/common'; import { getAirspaceList } from '../../logic/airspaces'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; @customElement('airspace3d-element') export class Airspace3dElement extends connect(store)(LitElement) { diff --git a/apps/fxc-front/src/app/components/3d/controls3d-element.ts b/apps/fxc-front/src/app/components/3d/controls3d-element.ts index effe1236..7e988e8a 100644 --- a/apps/fxc-front/src/app/components/3d/controls3d-element.ts +++ b/apps/fxc-front/src/app/components/3d/controls3d-element.ts @@ -2,15 +2,17 @@ import '../dashboard-element'; import '../menu-element'; import '../name-element'; -import * as common from '@flyxc/common'; -import { css, CSSResult, html, LitElement, TemplateResult } from 'lit'; +import type * as common from '@flyxc/common'; +import type { CSSResult, TemplateResult } from 'lit'; +import { css, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; import { connect } from 'pwa-helpers'; -import * as units from '../../logic/units'; +import type * as units from '../../logic/units'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; @customElement('controls3d-element') export class Controls3dElement extends connect(store)(LitElement) { diff --git a/apps/fxc-front/src/app/components/3d/line3d-element.ts b/apps/fxc-front/src/app/components/3d/line3d-element.ts index 49b49915..96956759 100644 --- a/apps/fxc-front/src/app/components/3d/line3d-element.ts +++ b/apps/fxc-front/src/app/components/3d/line3d-element.ts @@ -1,14 +1,16 @@ import * as common from '@flyxc/common'; -import { LitElement, PropertyValues } from 'lit'; +import type { PropertyValues } from 'lit'; +import { LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; import Color from '@arcgis/core/Color'; import Graphic from '@arcgis/core/Graphic'; -import GraphicsLayer from '@arcgis/core/layers/GraphicsLayer'; +import type GraphicsLayer from '@arcgis/core/layers/GraphicsLayer'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; const INACTIVE_ALPHA = 0.7; diff --git a/apps/fxc-front/src/app/components/3d/map3d-element.ts b/apps/fxc-front/src/app/components/3d/map3d-element.ts index 63938a32..ed08173d 100644 --- a/apps/fxc-front/src/app/components/3d/map3d-element.ts +++ b/apps/fxc-front/src/app/components/3d/map3d-element.ts @@ -20,23 +20,25 @@ import VirtualLighting from '@arcgis/core/views/3d/environment/VirtualLighting'; import SceneView from '@arcgis/core/views/SceneView'; import Popup from '@arcgis/core/widgets/Popup'; import IntegratedMesh3DTilesLayer from '@arcgis/core/layers/IntegratedMesh3DTilesLayer.js'; -import { LatLon, LatLonAlt, RuntimeTrack } from '@flyxc/common'; +import type { LatLon, LatLonAlt, RuntimeTrack } from '@flyxc/common'; import { alertController } from '@ionic/core/components'; -import { LitElement, PropertyValues, TemplateResult, html } from 'lit'; +import type { PropertyValues, TemplateResult} from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; import { when } from 'lit/directives/when.js'; -import { UnsubscribeHandle } from 'micro-typed-events'; +import type { UnsubscribeHandle } from 'micro-typed-events'; import { connect } from 'pwa-helpers'; import * as msg from '../../logic/messages'; import { setApiLoading, setTimeSec, setView3d } from '../../redux/app-slice'; import { setCurrentLiveId } from '../../redux/live-track-slice'; import { setCurrentLocation, setCurrentZoom } from '../../redux/location-slice'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; import { setCurrentTrackId } from '../../redux/track-slice'; -import { Airspace3dElement } from './airspace3d-element'; -import { Skyways3dElement } from './skyways3d-element'; +import type { Airspace3dElement } from './airspace3d-element'; +import type { Skyways3dElement } from './skyways3d-element'; import { getApiKeyAndHost } from '../../apikey'; @customElement('map3d-element') diff --git a/apps/fxc-front/src/app/components/3d/marker3d-element.ts b/apps/fxc-front/src/app/components/3d/marker3d-element.ts index 8449f4d0..79d7596a 100644 --- a/apps/fxc-front/src/app/components/3d/marker3d-element.ts +++ b/apps/fxc-front/src/app/components/3d/marker3d-element.ts @@ -1,13 +1,15 @@ import * as common from '@flyxc/common'; -import { LitElement, PropertyValues } from 'lit'; +import type { PropertyValues } from 'lit'; +import { LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; import Graphic from '@arcgis/core/Graphic'; -import GraphicsLayer from '@arcgis/core/layers/GraphicsLayer'; +import type GraphicsLayer from '@arcgis/core/layers/GraphicsLayer'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; const MARKER_HEIGHT = 30; diff --git a/apps/fxc-front/src/app/components/3d/skyways3d-element.ts b/apps/fxc-front/src/app/components/3d/skyways3d-element.ts index b08484a0..422fed37 100644 --- a/apps/fxc-front/src/app/components/3d/skyways3d-element.ts +++ b/apps/fxc-front/src/app/components/3d/skyways3d-element.ts @@ -1,13 +1,15 @@ -import { LitElement, PropertyValues } from 'lit'; +import type { PropertyValues } from 'lit'; +import { LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; -import Map from '@arcgis/core/Map'; +import type Map from '@arcgis/core/Map'; import WebTileLayer from '@arcgis/core/layers/WebTileLayer'; import TileInfo from '@arcgis/core/layers/support/TileInfo'; import * as skyways from '../../redux/skyways-slice'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; @customElement('skyways3d-element') export class Skyways3dElement extends connect(store)(LitElement) { diff --git a/apps/fxc-front/src/app/components/3d/tracking3d-element.ts b/apps/fxc-front/src/app/components/3d/tracking3d-element.ts index 4f1f2eb4..56626a84 100644 --- a/apps/fxc-front/src/app/components/3d/tracking3d-element.ts +++ b/apps/fxc-front/src/app/components/3d/tracking3d-element.ts @@ -1,23 +1,27 @@ -import { protos } from '@flyxc/common'; -import { LitElement, PropertyValues } from 'lit'; +import type { protos } from '@flyxc/common'; +import type { PropertyValues } from 'lit'; +import { LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { UnsubscribeHandle } from 'micro-typed-events'; +import type { UnsubscribeHandle } from 'micro-typed-events'; import { connect } from 'pwa-helpers'; import Color from '@arcgis/core/Color'; import Point from '@arcgis/core/geometry/Point'; import Graphic from '@arcgis/core/Graphic'; -import GraphicsLayer from '@arcgis/core/layers/GraphicsLayer'; -import ElevationSampler from '@arcgis/core/layers/support/ElevationSampler'; -import SceneView from '@arcgis/core/views/SceneView'; +import type GraphicsLayer from '@arcgis/core/layers/GraphicsLayer'; +import type ElevationSampler from '@arcgis/core/layers/support/ElevationSampler'; +import type SceneView from '@arcgis/core/views/SceneView'; -import { FixType, LiveLineProperties, LivePointProperties } from '../../logic/live-track'; +import type { LiveLineProperties, LivePointProperties } from '../../logic/live-track'; +import { FixType } from '../../logic/live-track'; import { popupContent } from '../../logic/live-track-popup'; import * as msg from '../../logic/messages'; -import { formatDurationMin, Units } from '../../logic/units'; +import type { Units } from '../../logic/units'; +import { formatDurationMin } from '../../logic/units'; import { liveTrackSelectors, setCurrentLiveId } from '../../redux/live-track-slice'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; import { getUniqueContrastColor } from '../../styles/track'; // A track is considered recent if ended less than timeout ago. diff --git a/apps/fxc-front/src/app/components/admin/admin-page.ts b/apps/fxc-front/src/app/components/admin/admin-page.ts index ca0bea43..79c15297 100644 --- a/apps/fxc-front/src/app/components/admin/admin-page.ts +++ b/apps/fxc-front/src/app/components/admin/admin-page.ts @@ -1,6 +1,7 @@ import '@alenaksu/json-viewer'; import * as common from '@flyxc/common'; -import { html, LitElement, PropertyValues, TemplateResult } from 'lit'; +import type { PropertyValues, TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { when } from 'lit/directives/when.js'; diff --git a/apps/fxc-front/src/app/components/archives/archives-page.ts b/apps/fxc-front/src/app/components/archives/archives-page.ts index f7494d52..ce95e44b 100644 --- a/apps/fxc-front/src/app/components/archives/archives-page.ts +++ b/apps/fxc-front/src/app/components/archives/archives-page.ts @@ -1,5 +1,7 @@ -import { createPopper, Instance } from '@popperjs/core'; -import { html, LitElement, TemplateResult } from 'lit'; +import type { Instance } from '@popperjs/core'; +import { createPopper } from '@popperjs/core'; +import type { TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; import { getApiKeyAndHost } from '../../apikey'; diff --git a/apps/fxc-front/src/app/components/chart-element.ts b/apps/fxc-front/src/app/components/chart-element.ts index 16c75f9d..225f2033 100644 --- a/apps/fxc-front/src/app/components/chart-element.ts +++ b/apps/fxc-front/src/app/components/chart-element.ts @@ -1,6 +1,8 @@ -import { Class, Flags, isAirspaceVisible, RuntimeTrack, sampleAt, Type } from '@flyxc/common'; +import type { Class, RuntimeTrack, Type } from '@flyxc/common'; +import { Flags, isAirspaceVisible, sampleAt } from '@flyxc/common'; import { ticks } from 'd3-array'; -import { css, CSSResult, html, LitElement, PropertyValues, svg, SVGTemplateResult, TemplateResult } from 'lit'; +import type { CSSResult, PropertyValues, SVGTemplateResult, TemplateResult } from 'lit'; +import { css, html, LitElement, svg } from 'lit'; import { customElement, query, state } from 'lit/decorators.js'; import { guard } from 'lit/directives/guard.js'; import { connect } from 'pwa-helpers'; @@ -8,7 +10,8 @@ import { connect } from 'pwa-helpers'; import * as units from '../logic/units'; import { ChartYAxis, setChartYAxis } from '../redux/app-slice'; import * as sel from '../redux/selectors'; -import { RootState, store } from '../redux/store'; +import type { RootState} from '../redux/store'; +import { store } from '../redux/store'; const MIN_SPEED_FACTOR = 16; const MAX_SPEED_FACTOR = 4096; diff --git a/apps/fxc-front/src/app/components/dashboard-element.ts b/apps/fxc-front/src/app/components/dashboard-element.ts index aba064e2..2ca46999 100644 --- a/apps/fxc-front/src/app/components/dashboard-element.ts +++ b/apps/fxc-front/src/app/components/dashboard-element.ts @@ -1,7 +1,8 @@ import './ui/pref-modal'; import * as common from '@flyxc/common'; -import { css, CSSResult, html, LitElement, TemplateResult } from 'lit'; +import type { CSSResult, TemplateResult } from 'lit'; +import { css, html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { modalController } from '@ionic/core/components'; diff --git a/apps/fxc-front/src/app/components/devices/devices-page.ts b/apps/fxc-front/src/app/components/devices/devices-page.ts index 62cd29c5..5b1e737a 100644 --- a/apps/fxc-front/src/app/components/devices/devices-page.ts +++ b/apps/fxc-front/src/app/components/devices/devices-page.ts @@ -2,7 +2,8 @@ import { AccountFormModel, fetchResponse } from '@flyxc/common'; import { alertController } from '@ionic/core/components'; import { Binder, field } from '@vaadin/dom'; -import { LitElement, TemplateResult, html } from 'lit'; +import type { TemplateResult} from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, queryAll, state } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; import { setFetchMillis } from '../../redux/live-track-slice'; diff --git a/apps/fxc-front/src/app/components/devices/elements.ts b/apps/fxc-front/src/app/components/devices/elements.ts index eedfa32d..61131e4e 100644 --- a/apps/fxc-front/src/app/components/devices/elements.ts +++ b/apps/fxc-front/src/app/components/devices/elements.ts @@ -1,5 +1,6 @@ import * as common from '@flyxc/common'; -import { Binder, CheckedFieldStrategy, field, VaadinFieldStrategy } from '@vaadin/dom'; +import type { Binder} from '@vaadin/dom'; +import { CheckedFieldStrategy, field, VaadinFieldStrategy } from '@vaadin/dom'; import * as lit from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; diff --git a/apps/fxc-front/src/app/components/loader-element.ts b/apps/fxc-front/src/app/components/loader-element.ts index 85ee7fc0..971e02c8 100644 --- a/apps/fxc-front/src/app/components/loader-element.ts +++ b/apps/fxc-front/src/app/components/loader-element.ts @@ -1,7 +1,9 @@ -import { css, CSSResult, html, LitElement, PropertyValues, TemplateResult } from 'lit'; +import type { CSSResult, PropertyValues, TemplateResult } from 'lit'; +import { css, html, LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; -import { RootState, store } from '../redux/store'; +import type { RootState} from '../redux/store'; +import { store } from '../redux/store'; @customElement('loader-element') export class LoaderElement extends connect(store)(LitElement) { diff --git a/apps/fxc-front/src/app/components/menu-element.ts b/apps/fxc-front/src/app/components/menu-element.ts index 430b2a10..eeedb574 100644 --- a/apps/fxc-front/src/app/components/menu-element.ts +++ b/apps/fxc-front/src/app/components/menu-element.ts @@ -1,4 +1,5 @@ -import { CSSResult, html, LitElement, TemplateResult } from 'lit'; +import type { CSSResult, TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement } from 'lit/decorators.js'; import { controlStyle } from '../styles/control-style'; diff --git a/apps/fxc-front/src/app/components/name-element.ts b/apps/fxc-front/src/app/components/name-element.ts index 5d02a3aa..6d5388bb 100644 --- a/apps/fxc-front/src/app/components/name-element.ts +++ b/apps/fxc-front/src/app/components/name-element.ts @@ -1,7 +1,8 @@ import './ui/track-modal'; -import * as common from '@flyxc/common'; -import { CSSResult, html, LitElement, TemplateResult } from 'lit'; +import type * as common from '@flyxc/common'; +import type { CSSResult, TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { modalController } from '@ionic/core/components'; diff --git a/apps/fxc-front/src/app/components/ui/about-modal.ts b/apps/fxc-front/src/app/components/ui/about-modal.ts index 11584fa9..5606e1f7 100644 --- a/apps/fxc-front/src/app/components/ui/about-modal.ts +++ b/apps/fxc-front/src/app/components/ui/about-modal.ts @@ -1,4 +1,5 @@ -import { html, LitElement, TemplateResult } from 'lit'; +import type { TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement } from 'lit/decorators.js'; import { modalController } from '@ionic/core/components'; diff --git a/apps/fxc-front/src/app/components/ui/google-btn.ts b/apps/fxc-front/src/app/components/ui/google-btn.ts index 40783182..885773c4 100644 --- a/apps/fxc-front/src/app/components/ui/google-btn.ts +++ b/apps/fxc-front/src/app/components/ui/google-btn.ts @@ -1,4 +1,5 @@ -import { css, CSSResult, html, LitElement, TemplateResult } from 'lit'; +import type { CSSResult, TemplateResult } from 'lit'; +import { css, html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; diff --git a/apps/fxc-front/src/app/components/ui/live-modal.ts b/apps/fxc-front/src/app/components/ui/live-modal.ts index eeb7e5ef..44f62e5a 100644 --- a/apps/fxc-front/src/app/components/ui/live-modal.ts +++ b/apps/fxc-front/src/app/components/ui/live-modal.ts @@ -1,15 +1,18 @@ -import * as common from '@flyxc/common'; +import type * as common from '@flyxc/common'; import { modalController, toastController } from '@ionic/core/components'; import { getDistance } from 'geolib'; -import { LitElement, TemplateResult, html } from 'lit'; +import type { TemplateResult} from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; import { connect } from 'pwa-helpers'; import * as msg from '../../logic/messages'; import * as units from '../../logic/units'; -import { LivePilot, getLivePilots, setCenterOnLocation, setCurrentLiveId } from '../../redux/live-track-slice'; +import type { LivePilot} from '../../redux/live-track-slice'; +import { getLivePilots, setCenterOnLocation, setCurrentLiveId } from '../../redux/live-track-slice'; import { setCurrentLocation } from '../../redux/location-slice'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; import { getUniqueContrastColor } from '../../styles/track'; import { maybeHideSidePane } from '../../../flyxc'; diff --git a/apps/fxc-front/src/app/components/ui/main-menu.ts b/apps/fxc-front/src/app/components/ui/main-menu.ts index 66591ad7..5af66667 100644 --- a/apps/fxc-front/src/app/components/ui/main-menu.ts +++ b/apps/fxc-front/src/app/components/ui/main-menu.ts @@ -1,21 +1,25 @@ import { Class, Type, getClassName, getTypeName } from '@flyxc/common'; -import { SearchbarCustomEvent, ToggleCustomEvent, modalController, toastController } from '@ionic/core/components'; -import { LitElement, TemplateResult, html } from 'lit'; +import type { SearchbarCustomEvent, ToggleCustomEvent} from '@ionic/core/components'; +import { modalController, toastController } from '@ionic/core/components'; +import type { TemplateResult} from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { map } from 'lit/directives/map.js'; import { when } from 'lit/directives/when.js'; -import { UnsubscribeHandle } from 'micro-typed-events'; +import type { UnsubscribeHandle } from 'micro-typed-events'; import { connect } from 'pwa-helpers'; import { requestCurrentPosition } from '../../logic/geolocation'; import { ParamNames, addUrlParamValues, pushCurrentState } from '../../logic/history'; import * as msg from '../../logic/messages'; import { uploadTracks } from '../../logic/track'; -import { DistanceUnit, formatUnit } from '../../logic/units'; +import type { DistanceUnit} from '../../logic/units'; +import { formatUnit } from '../../logic/units'; import * as airspaces from '../../redux/airspace-slice'; import { setApiLoading } from '../../redux/app-slice'; import * as arcgis from '../../redux/arcgis-slice'; +import type { + LivePilot} from '../../redux/live-track-slice'; import { - LivePilot, getLivePilots, setDisplayLabels as setDisplayLiveLabels, setFetchMillis, @@ -26,7 +30,8 @@ import { import { setEnabled } from '../../redux/planner-slice'; import * as sel from '../../redux/selectors'; import * as skyways from '../../redux/skyways-slice'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; import { setDisplayLabels, setLockOnPilot } from '../../redux/track-slice'; import './about-modal'; import './live-modal'; diff --git a/apps/fxc-front/src/app/components/ui/pref-modal.ts b/apps/fxc-front/src/app/components/ui/pref-modal.ts index 8b1070d1..76a21e93 100644 --- a/apps/fxc-front/src/app/components/ui/pref-modal.ts +++ b/apps/fxc-front/src/app/components/ui/pref-modal.ts @@ -1,4 +1,5 @@ -import { html, LitElement, TemplateResult } from 'lit'; +import type { TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; @@ -6,7 +7,8 @@ import { modalController } from '@ionic/core/components'; import * as units from '../../logic/units'; import { setLeague } from '../../redux/planner-slice'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; import { setAltitudeUnit, setDistanceUnit, setSpeedUnit, setVarioUnit } from '../../redux/units-slice'; import { LEAGUE_CODES, LEAGUES } from '../../logic/score/league/leagues'; diff --git a/apps/fxc-front/src/app/components/ui/share-modal.ts b/apps/fxc-front/src/app/components/ui/share-modal.ts index aad6140f..e275d065 100644 --- a/apps/fxc-front/src/app/components/ui/share-modal.ts +++ b/apps/fxc-front/src/app/components/ui/share-modal.ts @@ -1,9 +1,11 @@ -import { encodeFloats, encodeSignedIntegers, LatLonAlt } from '@flyxc/common'; -import { html, LitElement, PropertyValues, TemplateResult } from 'lit'; +import type { LatLonAlt } from '@flyxc/common'; +import { encodeFloats, encodeSignedIntegers } from '@flyxc/common'; +import type { PropertyValues, TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { toDataURL } from 'qrcode/lib/browser'; -import { SegmentCustomEvent } from '@ionic/core'; +import type { SegmentCustomEvent } from '@ionic/core'; import { modalController, toastController } from '@ionic/core/components'; @customElement('share-modal') diff --git a/apps/fxc-front/src/app/components/ui/supporter-modal.ts b/apps/fxc-front/src/app/components/ui/supporter-modal.ts index c8ccddd2..8ca64728 100644 --- a/apps/fxc-front/src/app/components/ui/supporter-modal.ts +++ b/apps/fxc-front/src/app/components/ui/supporter-modal.ts @@ -1,4 +1,5 @@ -import { html, LitElement, TemplateResult } from 'lit'; +import type { TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement } from 'lit/decorators.js'; import { modalController } from '@ionic/core/components'; diff --git a/apps/fxc-front/src/app/components/ui/track-modal.ts b/apps/fxc-front/src/app/components/ui/track-modal.ts index 7d2f812d..da2e5a18 100644 --- a/apps/fxc-front/src/app/components/ui/track-modal.ts +++ b/apps/fxc-front/src/app/components/ui/track-modal.ts @@ -1,5 +1,7 @@ -import { extractGroupId, RuntimeTrack } from '@flyxc/common'; -import { html, LitElement, TemplateResult } from 'lit'; +import type { RuntimeTrack } from '@flyxc/common'; +import { extractGroupId } from '@flyxc/common'; +import type { TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { connect } from 'pwa-helpers'; @@ -9,7 +11,8 @@ import { pushCurrentState } from '../../logic/history'; import * as msg from '../../logic/messages'; import * as app from '../../redux/app-slice'; import * as sel from '../../redux/selectors'; -import { RootState, store } from '../../redux/store'; +import type { RootState} from '../../redux/store'; +import { store } from '../../redux/store'; import * as trackSlice from '../../redux/track-slice'; import { maybeHideSidePane } from '../../../flyxc'; diff --git a/apps/fxc-front/src/app/components/ui/waypoint-modal.ts b/apps/fxc-front/src/app/components/ui/waypoint-modal.ts index 0aaba1f6..727d9de8 100644 --- a/apps/fxc-front/src/app/components/ui/waypoint-modal.ts +++ b/apps/fxc-front/src/app/components/ui/waypoint-modal.ts @@ -1,5 +1,6 @@ -import { LatLonAlt } from '@flyxc/common'; -import { html, LitElement, TemplateResult } from 'lit'; +import type { LatLonAlt } from '@flyxc/common'; +import type { TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { modalController } from '@ionic/core/components'; diff --git a/apps/fxc-front/src/app/gm/fai-sectors.ts b/apps/fxc-front/src/app/gm/fai-sectors.ts index af611ca8..bfcfeca2 100644 --- a/apps/fxc-front/src/app/gm/fai-sectors.ts +++ b/apps/fxc-front/src/app/gm/fai-sectors.ts @@ -1,6 +1,6 @@ import { getDistance, getGreatCircleBearing, toDeg, toRad } from 'geolib'; -import { LatLon } from '@flyxc/common'; +import type { LatLon } from '@flyxc/common'; const SECTOR_COLORS = ['#f00', '#0f0', '#00f']; diff --git a/apps/fxc-front/src/app/logic/airspaces.ts b/apps/fxc-front/src/app/logic/airspaces.ts index 12c8c125..c3ec22e5 100644 --- a/apps/fxc-front/src/app/logic/airspaces.ts +++ b/apps/fxc-front/src/app/logic/airspaces.ts @@ -1,12 +1,13 @@ -import { - AIRSPACE_TILE_SIZE, +import type { AirspaceString, AirspaceTyped, Class, LatLon, - MAX_AIRSPACE_TILE_ZOOM, Point, - Type, + Type} from '@flyxc/common'; +import { + AIRSPACE_TILE_SIZE, + MAX_AIRSPACE_TILE_ZOOM, getAirspaceCategory, getAirspaceColor, getAirspaceTileUrl, diff --git a/apps/fxc-front/src/app/logic/elevation.ts b/apps/fxc-front/src/app/logic/elevation.ts index 4f1f10c7..ce883dcb 100644 --- a/apps/fxc-front/src/app/logic/elevation.ts +++ b/apps/fxc-front/src/app/logic/elevation.ts @@ -1,4 +1,4 @@ -import { LatLon, LatLonAlt } from '@flyxc/common'; +import type { LatLon, LatLonAlt } from '@flyxc/common'; // Adds the ground elevation to the list of points. // diff --git a/apps/fxc-front/src/app/logic/live-track-popup.ts b/apps/fxc-front/src/app/logic/live-track-popup.ts index 103006e5..6e4e34b5 100644 --- a/apps/fxc-front/src/app/logic/live-track-popup.ts +++ b/apps/fxc-front/src/app/logic/live-track-popup.ts @@ -2,7 +2,8 @@ import { getFixMessage, getTrackerDisplayName, isEmergencyFix, isLowBatFix, isVa import { liveTrackSelectors } from '../redux/live-track-slice'; import { store } from '../redux/store'; -import { formatUnit, Units } from './units'; +import type { Units } from './units'; +import { formatUnit } from './units'; // Generates the content of the live tracking popup. export function popupContent( diff --git a/apps/fxc-front/src/app/logic/live-track.ts b/apps/fxc-front/src/app/logic/live-track.ts index 2a0ca68f..9e20a0b8 100644 --- a/apps/fxc-front/src/app/logic/live-track.ts +++ b/apps/fxc-front/src/app/logic/live-track.ts @@ -1,3 +1,5 @@ +import type { + protos} from '@flyxc/common'; import { differentialDecodeLiveTrack, getFixMessage, @@ -7,7 +9,6 @@ import { isUfo, LIVE_MINIMAL_INTERVAL_SEC, mergeLiveTracks, - protos, simplifyLiveTrack, } from '@flyxc/common'; import { getRhumbLineBearing } from 'geolib'; diff --git a/apps/fxc-front/src/app/logic/messages.ts b/apps/fxc-front/src/app/logic/messages.ts index df1493d2..710e7b32 100644 --- a/apps/fxc-front/src/app/logic/messages.ts +++ b/apps/fxc-front/src/app/logic/messages.ts @@ -1,6 +1,6 @@ import type Graphic from '@arcgis/core/Graphic'; import type SceneView from '@arcgis/core/views/SceneView'; -import { LatLon, LatLonAlt } from '@flyxc/common'; +import type { LatLon, LatLonAlt } from '@flyxc/common'; import { createEvents } from 'micro-typed-events'; // Zoom the map in the given direction (typically mouse wheel). diff --git a/apps/fxc-front/src/app/logic/score/league/leagues.ts b/apps/fxc-front/src/app/logic/score/league/leagues.ts index 7ccebba2..56ff2491 100644 --- a/apps/fxc-front/src/app/logic/score/league/leagues.ts +++ b/apps/fxc-front/src/app/logic/score/league/leagues.ts @@ -1,4 +1,4 @@ -import { ScoringRuleName } from '@flyxc/optimizer'; +import type { ScoringRuleName } from '@flyxc/optimizer'; export const LEAGUE_CODES = [ 'czl', diff --git a/apps/fxc-front/src/app/redux/airspace-slice.ts b/apps/fxc-front/src/app/redux/airspace-slice.ts index 53d5fcfb..8f8c648c 100644 --- a/apps/fxc-front/src/app/redux/airspace-slice.ts +++ b/apps/fxc-front/src/app/redux/airspace-slice.ts @@ -1,5 +1,6 @@ import { Class, Type } from '@flyxc/common'; -import { PayloadAction, createSlice } from '@reduxjs/toolkit'; +import type { PayloadAction} from '@reduxjs/toolkit'; +import { createSlice } from '@reduxjs/toolkit'; type AirspaceState = { maxAltitude: number; diff --git a/apps/fxc-front/src/app/redux/app-slice.ts b/apps/fxc-front/src/app/redux/app-slice.ts index 49e1eb13..ae900a7d 100644 --- a/apps/fxc-front/src/app/redux/app-slice.ts +++ b/apps/fxc-front/src/app/redux/app-slice.ts @@ -1,4 +1,5 @@ -import { createSlice, PayloadAction, Store } from '@reduxjs/toolkit'; +import type { PayloadAction, Store } from '@reduxjs/toolkit'; +import { createSlice } from '@reduxjs/toolkit'; export const UPDATE_APP_TIME_EVERY_MIN = 10; diff --git a/apps/fxc-front/src/app/redux/arcgis-slice.ts b/apps/fxc-front/src/app/redux/arcgis-slice.ts index fc1e4fb8..c05063cc 100644 --- a/apps/fxc-front/src/app/redux/arcgis-slice.ts +++ b/apps/fxc-front/src/app/redux/arcgis-slice.ts @@ -1,4 +1,5 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import type { PayloadAction } from '@reduxjs/toolkit'; +import { createSlice } from '@reduxjs/toolkit'; type ArcgisState = { // Altitude exaggeration multiplier for 3d. diff --git a/apps/fxc-front/src/app/redux/browser-slice.ts b/apps/fxc-front/src/app/redux/browser-slice.ts index 50e46d30..8c820486 100644 --- a/apps/fxc-front/src/app/redux/browser-slice.ts +++ b/apps/fxc-front/src/app/redux/browser-slice.ts @@ -1,5 +1,6 @@ import { getHostName } from '@flyxc/common'; -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import type { PayloadAction } from '@reduxjs/toolkit'; +import { createSlice } from '@reduxjs/toolkit'; import { store } from './store'; type BrowserState = { diff --git a/apps/fxc-front/src/app/redux/live-track-slice.ts b/apps/fxc-front/src/app/redux/live-track-slice.ts index a2f7baf7..6744368f 100644 --- a/apps/fxc-front/src/app/redux/live-track-slice.ts +++ b/apps/fxc-front/src/app/redux/live-track-slice.ts @@ -1,18 +1,21 @@ -import { getLastMessage, isEmergencyTrack, LatLonAlt, protos } from '@flyxc/common'; +import type { LatLonAlt, protos } from '@flyxc/common'; +import { getLastMessage, isEmergencyTrack } from '@flyxc/common'; +import type { + EntityState, + PayloadAction} from '@reduxjs/toolkit'; import { createAsyncThunk, createEntityAdapter, createSelector, - createSlice, - EntityState, - PayloadAction, + createSlice } from '@reduxjs/toolkit'; import type { Response } from '../workers/live-track'; import LiveTrackWorker from '../workers/live-track?worker'; import { isMobile } from './browser-slice'; -import { RootState, store } from './store'; +import type { RootState} from './store'; +import { store } from './store'; // Refresh live tracks every. const REFRESH_INTERVAL_SEC = isMobile() ? 2 * 60 : 60; diff --git a/apps/fxc-front/src/app/redux/location-slice.ts b/apps/fxc-front/src/app/redux/location-slice.ts index 52a578dc..96cba684 100644 --- a/apps/fxc-front/src/app/redux/location-slice.ts +++ b/apps/fxc-front/src/app/redux/location-slice.ts @@ -1,6 +1,7 @@ -import { LatLon } from '@flyxc/common'; +import type { LatLon } from '@flyxc/common'; -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import type { PayloadAction } from '@reduxjs/toolkit'; +import { createSlice } from '@reduxjs/toolkit'; type State = { // Current location and zoom level. diff --git a/apps/fxc-front/src/app/redux/planner-slice.ts b/apps/fxc-front/src/app/redux/planner-slice.ts index 1e80905c..36c28dec 100644 --- a/apps/fxc-front/src/app/redux/planner-slice.ts +++ b/apps/fxc-front/src/app/redux/planner-slice.ts @@ -1,8 +1,9 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import type { PayloadAction } from '@reduxjs/toolkit'; +import { createSlice } from '@reduxjs/toolkit'; import { deleteUrlParam, getUrlParamValues, ParamNames, setUrlParamValue } from '../logic/history'; -import { Score } from '../logic/score/scorer'; -import { LeagueCode } from '../logic/score/league/leagues'; +import type { Score } from '../logic/score/scorer'; +import type { LeagueCode } from '../logic/score/league/leagues'; export type PlannerState = { score?: Score; diff --git a/apps/fxc-front/src/app/redux/selectors.ts b/apps/fxc-front/src/app/redux/selectors.ts index dc42220c..4e789bce 100644 --- a/apps/fxc-front/src/app/redux/selectors.ts +++ b/apps/fxc-front/src/app/redux/selectors.ts @@ -1,9 +1,11 @@ -import { extractGroupId, LatLon, LatLonAlt, RuntimeTrack, sampleAt } from '@flyxc/common'; +import type { LatLon, LatLonAlt, RuntimeTrack} from '@flyxc/common'; +import { extractGroupId, sampleAt } from '@flyxc/common'; import { createSelector } from 'reselect'; -import { DistanceUnit, Units } from '../logic/units'; +import type { Units } from '../logic/units'; +import { DistanceUnit } from '../logic/units'; import { getUniqueColor } from '../styles/track'; -import { RootState } from './store'; +import type { RootState } from './store'; import { trackAdapterSelector } from './track-slice'; export const units = (state: RootState): Units => state.units; diff --git a/apps/fxc-front/src/app/redux/skyways-slice.ts b/apps/fxc-front/src/app/redux/skyways-slice.ts index f2f9ed92..a75e694e 100644 --- a/apps/fxc-front/src/app/redux/skyways-slice.ts +++ b/apps/fxc-front/src/app/redux/skyways-slice.ts @@ -2,8 +2,9 @@ // // See https://thermal.kk7.ch -import { createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { RootState } from './store'; +import type { PayloadAction } from '@reduxjs/toolkit'; +import { createSelector, createSlice } from '@reduxjs/toolkit'; +import type { RootState } from './store'; const TILE_URL = 'https://thermal.kk7.ch/tiles/{layer}/{z}/{x}/{y}.png?src={domain}'.replace( '{domain}', diff --git a/apps/fxc-front/src/app/redux/store.ts b/apps/fxc-front/src/app/redux/store.ts index 649522ed..98827e20 100644 --- a/apps/fxc-front/src/app/redux/store.ts +++ b/apps/fxc-front/src/app/redux/store.ts @@ -1,6 +1,7 @@ -import { ThunkAction } from 'redux-thunk'; +import type { ThunkAction } from 'redux-thunk'; -import { Action, DevToolsEnhancerOptions, combineReducers, configureStore } from '@reduxjs/toolkit'; +import type { Action, DevToolsEnhancerOptions} from '@reduxjs/toolkit'; +import { combineReducers, configureStore } from '@reduxjs/toolkit'; import * as airspace from './airspace-slice'; import * as app from './app-slice'; diff --git a/apps/fxc-front/src/app/redux/track-slice.ts b/apps/fxc-front/src/app/redux/track-slice.ts index ca946901..62e50c3b 100644 --- a/apps/fxc-front/src/app/redux/track-slice.ts +++ b/apps/fxc-front/src/app/redux/track-slice.ts @@ -1,20 +1,22 @@ +import type { + RuntimeTrack} from '@flyxc/common'; import { addAirspaces, addGroundAltitude, createRuntimeTracks, createTrackId, extractGroupId, - protos, - RuntimeTrack, + protos } from '@flyxc/common'; -import { createAsyncThunk, createEntityAdapter, createSlice, EntityState, PayloadAction } from '@reduxjs/toolkit'; +import type { EntityState, PayloadAction } from '@reduxjs/toolkit'; +import { createAsyncThunk, createEntityAdapter, createSlice } from '@reduxjs/toolkit'; import { addUrlParamValue, deleteUrlParamValue, ParamNames } from '../logic/history'; import * as msg from '../logic/messages'; import type { Response } from '../workers/track'; import TrackWorker from '../workers/track?worker'; import { setTimeSec } from './app-slice'; import { setEnabled, setRoute } from './planner-slice'; -import { AppDispatch, AppThunk, RootState } from './store'; +import type { AppDispatch, AppThunk, RootState } from './store'; const FETCH_EVERY_SECONDS = 15; export const FETCH_FOR_MINUTES = 3; diff --git a/apps/fxc-front/src/app/redux/units-slice.ts b/apps/fxc-front/src/app/redux/units-slice.ts index 9a87a540..78237a4a 100644 --- a/apps/fxc-front/src/app/redux/units-slice.ts +++ b/apps/fxc-front/src/app/redux/units-slice.ts @@ -1,6 +1,8 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import type { PayloadAction } from '@reduxjs/toolkit'; +import { createSlice } from '@reduxjs/toolkit'; -import { DistanceUnit, SpeedUnit, Units } from '../logic/units'; +import type { Units } from '../logic/units'; +import { DistanceUnit, SpeedUnit } from '../logic/units'; const initialState: Units = { distance: (localStorage.getItem('unit.distance') ?? DistanceUnit.Kilometers) as DistanceUnit, diff --git a/apps/fxc-front/src/app/workers/track.ts b/apps/fxc-front/src/app/workers/track.ts index fdfb379c..995fa327 100644 --- a/apps/fxc-front/src/app/workers/track.ts +++ b/apps/fxc-front/src/app/workers/track.ts @@ -1,7 +1,8 @@ // Filter the altitude using a median filter. // Compute the heading. -import { computeVerticalSpeed, RuntimeTrack } from '@flyxc/common'; +import type { RuntimeTrack } from '@flyxc/common'; +import { computeVerticalSpeed } from '@flyxc/common'; import { getRhumbLineBearing } from 'geolib'; import createMedianFilter from 'moving-median'; diff --git a/apps/fxc-front/src/env.d.ts b/apps/fxc-front/src/env.d.ts index 1f62738a..5ad68dc8 100644 --- a/apps/fxc-front/src/env.d.ts +++ b/apps/fxc-front/src/env.d.ts @@ -1,7 +1,7 @@ /// /// -import { AirspaceServer } from '@flyxc/common'; +import type { AirspaceServer } from '@flyxc/common'; interface ImportMetaEnv { VITE_AIRSPACE_SERVER: AirspaceServer; diff --git a/apps/fxc-front/src/flyxc.ts b/apps/fxc-front/src/flyxc.ts index 0a2e768b..b7f29b98 100644 --- a/apps/fxc-front/src/flyxc.ts +++ b/apps/fxc-front/src/flyxc.ts @@ -11,14 +11,15 @@ import './app/components/chart-element'; import './app/components/loader-element'; import './app/components/ui/main-menu'; -import { LatLonAlt } from '@flyxc/common'; -import { html, LitElement, TemplateResult } from 'lit'; +import type { LatLonAlt } from '@flyxc/common'; +import type { TemplateResult } from 'lit'; +import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { when } from 'lit/directives/when.js'; import { connect } from 'pwa-helpers'; -import { NavigationHookResult } from '@ionic/core/dist/types/components/route/route-interface'; +import type { NavigationHookResult } from '@ionic/core/dist/types/components/route/route-interface'; import { ionicInit } from './app/components/ui/ionic'; import { requestCurrentPosition } from './app/logic/geolocation'; @@ -36,7 +37,8 @@ import { downloadTracksByGroupIds, downloadTracksByUrls, uploadTracks } from './ import * as app from './app/redux/app-slice'; import * as planner from './app/redux/planner-slice'; import * as sel from './app/redux/selectors'; -import { RootState, store } from './app/redux/store'; +import type { RootState} from './app/redux/store'; +import { store } from './app/redux/store'; import * as track from './app/redux/track-slice'; export const SHOW_SPLIT_PANE_WHEN = `(min-width: 992px)`; diff --git a/apps/fxc-server/src/app/parser/geojson.ts b/apps/fxc-server/src/app/parser/geojson.ts index e1b04d1c..e16ff6f9 100644 --- a/apps/fxc-server/src/app/parser/geojson.ts +++ b/apps/fxc-server/src/app/parser/geojson.ts @@ -1,4 +1,4 @@ -import { protos } from '@flyxc/common'; +import type { protos } from '@flyxc/common'; // Parse a GeoJson track to a proto message. export function parseGeoJson(geojson: any): protos.Track[] { diff --git a/apps/fxc-server/src/app/parser/igc.ts b/apps/fxc-server/src/app/parser/igc.ts index 61db5b40..771578f4 100644 --- a/apps/fxc-server/src/app/parser/igc.ts +++ b/apps/fxc-server/src/app/parser/igc.ts @@ -1,4 +1,4 @@ -import { protos } from '@flyxc/common'; +import type { protos } from '@flyxc/common'; import IGCParser from 'igc-parser'; export function parse(content: string): protos.Track[] { diff --git a/apps/fxc-server/src/app/parser/kml.ts b/apps/fxc-server/src/app/parser/kml.ts index 69a7ac84..2df0efcf 100644 --- a/apps/fxc-server/src/app/parser/kml.ts +++ b/apps/fxc-server/src/app/parser/kml.ts @@ -1,4 +1,4 @@ -import { protos } from '@flyxc/common'; +import type { protos } from '@flyxc/common'; import * as toGeoJSON from '@tmcw/togeojson'; import { DOMParser } from '@xmldom/xmldom'; diff --git a/apps/fxc-server/src/app/parser/parser.ts b/apps/fxc-server/src/app/parser/parser.ts index 746562e5..9fc6ee2d 100644 --- a/apps/fxc-server/src/app/parser/parser.ts +++ b/apps/fxc-server/src/app/parser/parser.ts @@ -1,12 +1,13 @@ import { diffEncodeTrack, fetchResponse, formatReqError, protos } from '@flyxc/common'; +import type { + TrackEntity} from '@flyxc/common-node'; import { retrieveMetaTrackGroupByHash, retrieveMetaTrackGroupByUrl, saveTrack, - TrackEntity, queueTrackPostProcessing, } from '@flyxc/common-node'; -import { Datastore } from '@google-cloud/datastore'; +import type { Datastore } from '@google-cloud/datastore'; import * as crypto from 'node:crypto'; import { parse as parseGpx, parseRoute as parseGpxRoute } from './gpx'; import { parse as parseIgc } from './igc'; diff --git a/apps/fxc-server/src/app/parser/trk.ts b/apps/fxc-server/src/app/parser/trk.ts index dfff584c..421f37c8 100644 --- a/apps/fxc-server/src/app/parser/trk.ts +++ b/apps/fxc-server/src/app/parser/trk.ts @@ -1,4 +1,4 @@ -import { protos } from '@flyxc/common'; +import type { protos } from '@flyxc/common'; const months: { [key: string]: number } = { JAN: 0, diff --git a/apps/fxc-server/src/app/routes/admin.ts b/apps/fxc-server/src/app/routes/admin.ts index ef297ad3..86cb57a6 100644 --- a/apps/fxc-server/src/app/routes/admin.ts +++ b/apps/fxc-server/src/app/routes/admin.ts @@ -1,8 +1,9 @@ import csurf from '@dr.pogodin/csurf'; import { AccountFormModel, Keys, trackerNames, ufoFleetNames } from '@flyxc/common'; import { TRACK_TABLE, retrieveLiveTrackById, retrieveRecentTracks } from '@flyxc/common-node'; -import { NextFunction, Request, Response, Router } from 'express'; -import { Redis } from 'ioredis'; +import type { NextFunction, Request, Response} from 'express'; +import { Router } from 'express'; +import type { Redis } from 'ioredis'; import zlib from 'node:zlib'; import { Datastore } from '@google-cloud/datastore'; diff --git a/apps/fxc-server/src/app/routes/live-track.ts b/apps/fxc-server/src/app/routes/live-track.ts index cf4f84be..56793fae 100644 --- a/apps/fxc-server/src/app/routes/live-track.ts +++ b/apps/fxc-server/src/app/routes/live-track.ts @@ -1,11 +1,12 @@ import csurf from '@dr.pogodin/csurf'; +import type { + AccountModel, + LiveTrackEntity} from '@flyxc/common'; import { AccountFormModel, - AccountModel, LONG_INCREMENTAL_UPDATE_SEC, SHORT_INCREMENTAL_UPDATE_SEC, Keys, - LiveTrackEntity, protos, SecretKeys, } from '@flyxc/common'; @@ -19,8 +20,9 @@ import { } from '@flyxc/common-node'; import { Datastore } from '@google-cloud/datastore'; import { NoDomBinder } from '@vaadin/nodom'; -import { Request, Response, Router } from 'express'; -import { Redis } from 'ioredis'; +import type { Request, Response} from 'express'; +import { Router } from 'express'; +import type { Redis } from 'ioredis'; import { getUserInfo, isLoggedIn, logout } from './session'; // Store the token in the session. diff --git a/apps/fxc-server/src/app/routes/session.ts b/apps/fxc-server/src/app/routes/session.ts index 81fda9c5..55c9a270 100644 --- a/apps/fxc-server/src/app/routes/session.ts +++ b/apps/fxc-server/src/app/routes/session.ts @@ -1,5 +1,5 @@ import { SecretKeys } from '@flyxc/common'; -import { Request } from 'express'; +import type { Request } from 'express'; const adminEmails = SecretKeys.ADMINS.split(','); diff --git a/apps/fxc-server/src/app/routes/supporters.ts b/apps/fxc-server/src/app/routes/supporters.ts index 423c0017..da759e93 100644 --- a/apps/fxc-server/src/app/routes/supporters.ts +++ b/apps/fxc-server/src/app/routes/supporters.ts @@ -1,6 +1,7 @@ import { Keys } from '@flyxc/common'; -import { Request, Response, Router } from 'express'; -import { Redis } from 'ioredis'; +import type { Request, Response} from 'express'; +import { Router } from 'express'; +import type { Redis } from 'ioredis'; export function getSupportersRouter(redis: Redis): Router { const router = Router(); diff --git a/apps/fxc-server/src/app/routes/track.ts b/apps/fxc-server/src/app/routes/track.ts index e78b2613..03562191 100644 --- a/apps/fxc-server/src/app/routes/track.ts +++ b/apps/fxc-server/src/app/routes/track.ts @@ -4,9 +4,10 @@ import { retrieveMetaTrackGroupByUrl, retrieveMetaTrackGroupsByIds, } from '@flyxc/common-node'; -import { Datastore } from '@google-cloud/datastore'; -import { Request, Response, Router } from 'express'; -import { UploadedFile } from 'express-fileupload'; +import type { Datastore } from '@google-cloud/datastore'; +import type { Request, Response} from 'express'; +import { Router } from 'express'; +import type { UploadedFile } from 'express-fileupload'; import { parse, parseFromUrl, parseRoute } from '../parser/parser'; diff --git a/apps/fxc-server/src/app/routes/waypoints.ts b/apps/fxc-server/src/app/routes/waypoints.ts index 6b2418a8..d7f90544 100644 --- a/apps/fxc-server/src/app/routes/waypoints.ts +++ b/apps/fxc-server/src/app/routes/waypoints.ts @@ -1,4 +1,5 @@ -import { Request, Response, Router } from 'express'; +import type { Request, Response} from 'express'; +import { Router } from 'express'; import { encode } from '../waypoints/waypoints'; export function getWaypointRouter(): Router { diff --git a/apps/fxc-server/src/app/routes/zoleo.ts b/apps/fxc-server/src/app/routes/zoleo.ts index ddbf2a98..7a41ae30 100644 --- a/apps/fxc-server/src/app/routes/zoleo.ts +++ b/apps/fxc-server/src/app/routes/zoleo.ts @@ -1,17 +1,19 @@ import { Keys, SecretKeys, fetchResponse, round } from '@flyxc/common'; +import type { + ZoleoMessage} from '@flyxc/common-node'; import { LIVE_TRACK_TABLE, ZOLEO_MAX_MSG, ZOLEO_MAX_MSG_SIZE, - ZoleoMessage, getDatastore, pushListCap, retrieveLiveTrackByGoogleId, } from '@flyxc/common-node'; import { Datastore } from '@google-cloud/datastore'; -import { Request, Response, Router } from 'express'; +import type { Request, Response} from 'express'; +import { Router } from 'express'; import basicAuth from 'express-basic-auth'; -import Redis from 'ioredis'; +import type Redis from 'ioredis'; import { pathGet } from 'object-standard-path'; import { getUserInfo, isLoggedIn } from './session'; diff --git a/apps/fxc-server/src/app/waypoints/waypoints.ts b/apps/fxc-server/src/app/waypoints/waypoints.ts index b5ce6f15..0d8d54e6 100644 --- a/apps/fxc-server/src/app/waypoints/waypoints.ts +++ b/apps/fxc-server/src/app/waypoints/waypoints.ts @@ -2,7 +2,8 @@ const { buildGPX, BaseBuilder } = require('gpx-builder'); const builder = require('xmlbuilder'); -import { LatLonAlt, round } from '@flyxc/common'; +import type { LatLonAlt} from '@flyxc/common'; +import { round } from '@flyxc/common'; const printf = require('printf'); export function encode( diff --git a/apps/misc/src/app/email_inreach.ts b/apps/misc/src/app/email_inreach.ts index a0350ce1..3674193f 100644 --- a/apps/misc/src/app/email_inreach.ts +++ b/apps/misc/src/app/email_inreach.ts @@ -1,6 +1,7 @@ import { readFileSync } from 'node:fs'; import { setTimeout } from 'node:timers/promises'; -import { LiveTrackEntity, SecretKeys, trackerNames } from '@flyxc/common'; +import type { LiveTrackEntity} from '@flyxc/common'; +import { SecretKeys, trackerNames } from '@flyxc/common'; import { MailerSend, EmailParams, Sender, Recipient } from 'mailersend'; (async () => { diff --git a/apps/misc/src/app/list_flymaster.ts b/apps/misc/src/app/list_flymaster.ts index 89f25acf..12a31932 100644 --- a/apps/misc/src/app/list_flymaster.ts +++ b/apps/misc/src/app/list_flymaster.ts @@ -1,5 +1,5 @@ import { readFileSync } from 'node:fs'; -import { LiveTrackEntity } from '@flyxc/common'; +import type { LiveTrackEntity } from '@flyxc/common'; const trackers = JSON.parse(readFileSync(`${__dirname}/assets/trackers.json`, 'utf-8')) as LiveTrackEntity[]; diff --git a/apps/misc/src/app/list_trackers.ts b/apps/misc/src/app/list_trackers.ts index b548c1f3..c6dd55d6 100644 --- a/apps/misc/src/app/list_trackers.ts +++ b/apps/misc/src/app/list_trackers.ts @@ -1,7 +1,7 @@ import { LIVE_TRACK_TABLE } from '@flyxc/common-node'; -import { LiveTrackEntity } from '@flyxc/common'; +import type { LiveTrackEntity } from '@flyxc/common'; import { Datastore } from '@google-cloud/datastore'; -import { RunQueryResponse } from '@google-cloud/datastore/build/src/query'; +import type { RunQueryResponse } from '@google-cloud/datastore/build/src/query'; import { writeFileSync } from 'node:fs'; const datastore = new Datastore(); diff --git a/apps/misc/src/app/list_tracks.ts b/apps/misc/src/app/list_tracks.ts index 3f890be6..289ff581 100644 --- a/apps/misc/src/app/list_tracks.ts +++ b/apps/misc/src/app/list_tracks.ts @@ -1,6 +1,7 @@ -import { TrackEntity, TRACK_TABLE } from '@flyxc/common-node'; +import type { TrackEntity} from '@flyxc/common-node'; +import { TRACK_TABLE } from '@flyxc/common-node'; import { Datastore } from '@google-cloud/datastore'; -import { RunQueryResponse } from '@google-cloud/datastore/build/src/query'; +import type { RunQueryResponse } from '@google-cloud/datastore/build/src/query'; import { writeFileSync } from 'node:fs'; const datastore = new Datastore(); diff --git a/apps/misc/src/app/migrate.ts b/apps/misc/src/app/migrate.ts index 2336cb60..2cf6f27b 100644 --- a/apps/misc/src/app/migrate.ts +++ b/apps/misc/src/app/migrate.ts @@ -1,7 +1,9 @@ -import { diffEncodeAirspaces, LiveTrackEntity, protos, trackerNames } from '@flyxc/common'; -import { getDatastore, retrieveTrackById, TrackEntity, updateUnzippedTracks } from '@flyxc/common-node'; +import type { LiveTrackEntity} from '@flyxc/common'; +import { diffEncodeAirspaces, protos, trackerNames } from '@flyxc/common'; +import type { TrackEntity} from '@flyxc/common-node'; +import { getDatastore, retrieveTrackById, updateUnzippedTracks } from '@flyxc/common-node'; import { Datastore } from '@google-cloud/datastore'; -import { RunQueryResponse } from '@google-cloud/datastore/build/src/query'; +import type { RunQueryResponse } from '@google-cloud/datastore/build/src/query'; const datastore = getDatastore(); diff --git a/apps/proxy/src/main.ts b/apps/proxy/src/main.ts index e0a8208c..ffd40e5b 100644 --- a/apps/proxy/src/main.ts +++ b/apps/proxy/src/main.ts @@ -1,5 +1,6 @@ import { fetchResponse, protos, SecretKeys } from '@flyxc/common'; -import express, { Request, Response } from 'express'; +import type { Request, Response } from 'express'; +import express from 'express'; const app = express().use(express.raw()); diff --git a/apps/run/src/app/airspace.ts b/apps/run/src/app/airspace.ts index 9f6f7a2e..b0990bc8 100644 --- a/apps/run/src/app/airspace.ts +++ b/apps/run/src/app/airspace.ts @@ -1,8 +1,10 @@ +import type { + AirspaceString, + AirspaceTyped, + Point} from '@flyxc/common'; import { AIRSPACE_TILE_SIZE, AirspaceColorCategory, - AirspaceString, - AirspaceTyped, fetchResponse, Flags, getAirspaceColorCategory, @@ -10,13 +12,13 @@ import { isInFeature, MAX_AIRSPACE_TILE_ZOOM, pixelCoordinates, - Point, protos, toTypedAirspace, } from '@flyxc/common'; import async from 'async'; import { VectorTile } from 'mapbox-vector-tile'; -import { LRU, lru } from 'tiny-lru'; +import type { LRU} from 'tiny-lru'; +import { lru } from 'tiny-lru'; // Look MARGIN_METER above max altitude. const MARGIN_METER = 200; diff --git a/apps/run/src/app/altitude.ts b/apps/run/src/app/altitude.ts index 480537bf..d8716900 100644 --- a/apps/run/src/app/altitude.ts +++ b/apps/run/src/app/altitude.ts @@ -7,10 +7,12 @@ // - https://observablehq.com/@benjaminortizulloa/mapzen-dem, // - https://www.mapzen.com/blog/terrain-tile-service/ -import { fetchResponse, pixelCoordinates, protos } from '@flyxc/common'; +import type { protos } from '@flyxc/common'; +import { fetchResponse, pixelCoordinates } from '@flyxc/common'; import async from 'async'; import lodepng from 'lodepng'; -import { LRU, lru } from 'tiny-lru'; +import type { LRU} from 'tiny-lru'; +import { lru } from 'tiny-lru'; // Zoom level for the altitude tiles. const ZOOM_LEVEL = 10; diff --git a/apps/run/src/app/process.ts b/apps/run/src/app/process.ts index e3091097..2b00f374 100644 --- a/apps/run/src/app/process.ts +++ b/apps/run/src/app/process.ts @@ -6,8 +6,9 @@ import { protos, SecretKeys, } from '@flyxc/common'; -import { retrieveTrackById, saveTrack, TrackEntity } from '@flyxc/common-node'; -import { Datastore } from '@google-cloud/datastore'; +import type { TrackEntity } from '@flyxc/common-node'; +import { retrieveTrackById, saveTrack } from '@flyxc/common-node'; +import type { Datastore } from '@google-cloud/datastore'; import async from 'async'; import * as polyline from 'google-polyline'; import simplify from 'simplify-path'; diff --git a/apps/run/src/main.ts b/apps/run/src/main.ts index b813bedf..bc3a4033 100644 --- a/apps/run/src/main.ts +++ b/apps/run/src/main.ts @@ -1,5 +1,6 @@ import { getDatastore } from '@flyxc/common-node'; -import express, { Request, Response } from 'express'; +import type { Request, Response } from 'express'; +import express from 'express'; import { postProcessTrack } from './app/process'; const app = express().use(express.json()); diff --git a/libs/common-node/src/lib/datastore.ts b/libs/common-node/src/lib/datastore.ts index c437dc01..001548e7 100644 --- a/libs/common-node/src/lib/datastore.ts +++ b/libs/common-node/src/lib/datastore.ts @@ -1,4 +1,5 @@ -import { Datastore, Key } from '@google-cloud/datastore'; +import type { Key } from '@google-cloud/datastore'; +import { Datastore } from '@google-cloud/datastore'; let datastore: Datastore; diff --git a/libs/common-node/src/lib/live-track-entity.ts b/libs/common-node/src/lib/live-track-entity.ts index 7952257a..e75bfc41 100644 --- a/libs/common-node/src/lib/live-track-entity.ts +++ b/libs/common-node/src/lib/live-track-entity.ts @@ -1,5 +1,6 @@ -import { AccountModel, LiveTrackEntity, trackerNames } from '@flyxc/common'; -import { Datastore } from '@google-cloud/datastore'; +import type { AccountModel, LiveTrackEntity} from '@flyxc/common'; +import { trackerNames } from '@flyxc/common'; +import type { Datastore } from '@google-cloud/datastore'; export const LIVE_TRACK_TABLE = 'LiveTrack'; export const NAME_MAX_LENGTH = 30; diff --git a/libs/common-node/src/lib/redis.ts b/libs/common-node/src/lib/redis.ts index 033c935f..a8510a86 100644 --- a/libs/common-node/src/lib/redis.ts +++ b/libs/common-node/src/lib/redis.ts @@ -1,4 +1,5 @@ -import Redis, { ChainableCommander } from 'ioredis'; +import type { ChainableCommander } from 'ioredis'; +import Redis from 'ioredis'; import { SecretKeys } from '@flyxc/common'; diff --git a/libs/common-node/src/lib/track-entity.ts b/libs/common-node/src/lib/track-entity.ts index 658b702a..a2c239aa 100644 --- a/libs/common-node/src/lib/track-entity.ts +++ b/libs/common-node/src/lib/track-entity.ts @@ -1,5 +1,7 @@ -import { getHostName, protos } from '@flyxc/common'; -import { Datastore, Key } from '@google-cloud/datastore'; +import type { protos } from '@flyxc/common'; +import { getHostName } from '@flyxc/common'; +import type { Key } from '@google-cloud/datastore'; +import { Datastore } from '@google-cloud/datastore'; import * as zlib from 'node:zlib'; export const TRACK_TABLE = 'Track'; diff --git a/libs/common-node/src/lib/validators.ts b/libs/common-node/src/lib/validators.ts index 289a06f6..da84c53c 100644 --- a/libs/common-node/src/lib/validators.ts +++ b/libs/common-node/src/lib/validators.ts @@ -1,12 +1,13 @@ +import type { + TrackerEntity, + TrackerModel} from '@flyxc/common'; import { fetchResponse, SecretKeys, - TrackerEntity, - TrackerModel, validateInreachAccount, validateSkylinesAccount, } from '@flyxc/common'; -import { Validator } from '@vaadin/nodom'; +import type { Validator } from '@vaadin/nodom'; // Makes sure the account is not password protected. export class InreachValidator implements Validator { diff --git a/libs/common/src/lib/airspaces.ts b/libs/common/src/lib/airspaces.ts index 1ce318bf..22ae6689 100644 --- a/libs/common/src/lib/airspaces.ts +++ b/libs/common/src/lib/airspaces.ts @@ -1,6 +1,6 @@ -import { Feature } from 'mapbox-vector-tile'; +import type { Feature } from 'mapbox-vector-tile'; -import { Point } from './runtime-track'; +import type { Point } from './runtime-track'; // Maximium zoom level for the airspaces. export const MAX_AIRSPACE_TILE_ZOOM = 10; diff --git a/libs/common/src/lib/aprs.test.ts b/libs/common/src/lib/aprs.test.ts index b91df234..323bb396 100644 --- a/libs/common/src/lib/aprs.test.ts +++ b/libs/common/src/lib/aprs.test.ts @@ -1,4 +1,5 @@ -import { AprsPosition, generateAprsPosition, parseAprsPosition } from './aprs'; +import type { AprsPosition} from './aprs'; +import { generateAprsPosition, parseAprsPosition } from './aprs'; describe('parseAprsPosition', () => { it('return null if malformed position', () => { diff --git a/libs/common/src/lib/distance.ts b/libs/common/src/lib/distance.ts index 185f3acf..2d94bf4c 100644 --- a/libs/common/src/lib/distance.ts +++ b/libs/common/src/lib/distance.ts @@ -1,6 +1,6 @@ import { getDistance } from 'geolib'; -import { RuntimeTrack } from './runtime-track'; +import type { RuntimeTrack } from './runtime-track'; // Finds the closest fix to {lat, lon} across all the tracks. export function findClosestFix( diff --git a/libs/common/src/lib/live-track-entity.ts b/libs/common/src/lib/live-track-entity.ts index bf21b5cf..7efc9a85 100644 --- a/libs/common/src/lib/live-track-entity.ts +++ b/libs/common/src/lib/live-track-entity.ts @@ -1,4 +1,4 @@ -import { Datastore, Key } from '@google-cloud/datastore'; +import type { Datastore, Key } from '@google-cloud/datastore'; export interface TrackerEntity { enabled: boolean; diff --git a/libs/common/src/lib/live-track.ts b/libs/common/src/lib/live-track.ts index ed229b70..7cf3c00f 100644 --- a/libs/common/src/lib/live-track.ts +++ b/libs/common/src/lib/live-track.ts @@ -1,4 +1,5 @@ -import { LiveDifferentialTrack, LiveExtra, LiveTrack } from '../protos/live-track'; +import type { LiveDifferentialTrack, LiveExtra} from '../protos/live-track'; +import { LiveTrack } from '../protos/live-track'; import { diffDecodeArray, diffEncodeArray32bit, findIndexes } from './math'; import { deepCopy } from './util'; diff --git a/libs/common/src/lib/models.ts b/libs/common/src/lib/models.ts index 6c21b06b..a5af0f0e 100644 --- a/libs/common/src/lib/models.ts +++ b/libs/common/src/lib/models.ts @@ -1,5 +1,7 @@ // Models and validation for user data. +import type { + Validator} from '@vaadin/nodom'; import { BooleanModel, NotBlank, @@ -7,10 +9,10 @@ import { ObjectModel, Size, StringModel, - Validator, _getPropertyModel, } from '@vaadin/nodom'; -import { TrackerNames, trackerNames } from './live-track'; +import type { TrackerNames} from './live-track'; +import { trackerNames } from './live-track'; import type { LiveTrackEntity, TrackerEntity } from './live-track-entity'; // Client side model for an account. diff --git a/libs/common/src/lib/proj.ts b/libs/common/src/lib/proj.ts index 6111d1b6..92620141 100644 --- a/libs/common/src/lib/proj.ts +++ b/libs/common/src/lib/proj.ts @@ -1,5 +1,5 @@ import SphericalMercator from '@mapbox/sphericalmercator'; -import { LatLon, Point } from './runtime-track'; +import type { LatLon, Point } from './runtime-track'; const mercatorBySize = new Map(); diff --git a/libs/optimizer/src/lib/optimizer.spec.ts b/libs/optimizer/src/lib/optimizer.spec.ts index 423a086b..91e853be 100644 --- a/libs/optimizer/src/lib/optimizer.spec.ts +++ b/libs/optimizer/src/lib/optimizer.spec.ts @@ -1,5 +1,7 @@ -import { CircuitType, ScoringRequest, ScoringResult, getOptimizer } from './optimizer'; -import { ScoringRuleName, scoringRuleNames } from './scoring-rules'; +import type { ScoringRequest, ScoringResult} from './optimizer'; +import { CircuitType, getOptimizer } from './optimizer'; +import type { ScoringRuleName} from './scoring-rules'; +import { scoringRuleNames } from './scoring-rules'; import { computeDestinationPoint, getGreatCircleBearing, getPreciseDistance } from 'geolib'; import { createSegments } from './utils/create-segments'; import { mergeTracks } from './utils/merge-tracks'; diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index 2fd0d4e0..7323935d 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -1,8 +1,10 @@ // TODO: all console logs are commented out. In the future, we should use a logging library -import { solver, Solution } from 'igc-xc-score'; -import { BRecord, IGCFile } from 'igc-parser'; -import { ScoringRuleName, scoringRules } from './scoring-rules'; +import type { Solution } from 'igc-xc-score'; +import { solver } from 'igc-xc-score'; +import type { BRecord, IGCFile } from 'igc-parser'; +import type { ScoringRuleName} from './scoring-rules'; +import { scoringRules } from './scoring-rules'; // Minimum number of points in an igc-xc-score track. // See this issue https://github.com/mmomtchev/igc-xc-score/issues/231 diff --git a/libs/optimizer/src/lib/utils/create-segments.ts b/libs/optimizer/src/lib/utils/create-segments.ts index e2052a9e..e65071ad 100644 --- a/libs/optimizer/src/lib/utils/create-segments.ts +++ b/libs/optimizer/src/lib/utils/create-segments.ts @@ -1,4 +1,4 @@ -import { LatLonAltTime, ScoringTrack } from '../optimizer'; +import type { LatLonAltTime, ScoringTrack } from '../optimizer'; /** * Creates a track with segments. diff --git a/libs/optimizer/src/lib/utils/merge-tracks.ts b/libs/optimizer/src/lib/utils/merge-tracks.ts index c20219ec..eb65929b 100644 --- a/libs/optimizer/src/lib/utils/merge-tracks.ts +++ b/libs/optimizer/src/lib/utils/merge-tracks.ts @@ -1,4 +1,4 @@ -import { LatLonAltTime, ScoringTrack } from '../optimizer'; +import type { LatLonAltTime, ScoringTrack } from '../optimizer'; /** * Merge multiple tracks. diff --git a/libs/vaadin-dom/src/lib/Binder.ts b/libs/vaadin-dom/src/lib/Binder.ts index fb5f2838..eb9b446f 100644 --- a/libs/vaadin-dom/src/lib/Binder.ts +++ b/libs/vaadin-dom/src/lib/Binder.ts @@ -1,5 +1,7 @@ -import { AbstractModel, BinderConfiguration, ModelConstructor, NoDomBinder, _onChange } from '@vaadin/nodom'; -import { FieldStrategy, getDefaultFieldStrategy } from './Field'; +import type { AbstractModel, BinderConfiguration, ModelConstructor} from '@vaadin/nodom'; +import { NoDomBinder, _onChange } from '@vaadin/nodom'; +import type { FieldStrategy} from './Field'; +import { getDefaultFieldStrategy } from './Field'; export class Binder> extends NoDomBinder { /** diff --git a/libs/vaadin-dom/src/lib/Field.ts b/libs/vaadin-dom/src/lib/Field.ts index ecb5c7e0..d9616872 100644 --- a/libs/vaadin-dom/src/lib/Field.ts +++ b/libs/vaadin-dom/src/lib/Field.ts @@ -1,6 +1,9 @@ -import { AbstractModel, getBinderNode, _fromString } from '@vaadin/nodom'; -import { ElementPart, noChange, nothing, PropertyPart } from 'lit'; -import { directive, Directive, DirectiveParameters, PartInfo, PartType } from 'lit/directive.js'; +import type { AbstractModel} from '@vaadin/nodom'; +import { getBinderNode, _fromString } from '@vaadin/nodom'; +import type { ElementPart, PropertyPart } from 'lit'; +import { noChange, nothing } from 'lit'; +import type { DirectiveParameters, PartInfo} from 'lit/directive.js'; +import { directive, Directive, PartType } from 'lit/directive.js'; import type { Binder } from './Binder'; diff --git a/libs/vaadin-nodom/src/lib/BinderNode.ts b/libs/vaadin-nodom/src/lib/BinderNode.ts index e6221c2d..2b4f8c2b 100644 --- a/libs/vaadin-nodom/src/lib/BinderNode.ts +++ b/libs/vaadin-nodom/src/lib/BinderNode.ts @@ -16,6 +16,9 @@ // TODO: Fix dependency cycle import type { NoDomBinder } from './NoDomBinder'; +import type { + ModelConstructor, + ModelValue} from './Models'; import { _binderNode, _ItemModel, @@ -25,8 +28,6 @@ import { AbstractModel, ArrayModel, getBinderNode, - ModelConstructor, - ModelValue, ObjectModel, } from './Models'; diff --git a/libs/vaadin-nodom/src/lib/NoDomBinder.ts b/libs/vaadin-nodom/src/lib/NoDomBinder.ts index 58ef2030..0dbb0e94 100644 --- a/libs/vaadin-nodom/src/lib/NoDomBinder.ts +++ b/libs/vaadin-nodom/src/lib/NoDomBinder.ts @@ -1,12 +1,14 @@ import { BinderNode } from './BinderNode'; -import { _parent, AbstractModel, ModelConstructor } from './Models'; -import { +import type { AbstractModel, ModelConstructor } from './Models'; +import { _parent } from './Models'; +import type { InterpolateMessageCallback, + Validator, + ValueError} from './Validation'; +import { runValidator, ServerValidator, - ValidationError, - Validator, - ValueError, + ValidationError } from './Validation'; const _submitting = Symbol('submitting'); diff --git a/libs/vaadin-nodom/src/lib/Validation.ts b/libs/vaadin-nodom/src/lib/Validation.ts index 1dc9fdc6..20048694 100644 --- a/libs/vaadin-nodom/src/lib/Validation.ts +++ b/libs/vaadin-nodom/src/lib/Validation.ts @@ -1,7 +1,8 @@ // TODO: Fix dependency cycle import type { BinderNode } from './BinderNode'; -import { AbstractModel, getBinderNode, NumberModel } from './Models'; +import type { AbstractModel} from './Models'; +import { getBinderNode, NumberModel } from './Models'; import type { NoDomBinder } from './NoDomBinder'; import { Required } from './Validators'; From 423df3a360600f650d902c0c971948bedfdcb969 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 3 Jun 2024 12:45:18 +0200 Subject: [PATCH 12/20] update docs --- README.md | 4 ++-- libs/optimizer/README.md | 18 +++++------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 04c5e0c9..1efd8337 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,6 @@ - Ufo 3d model by [pawinc](https://sketchfab.com/demarerik), - the many open source libraries, projects, and data sources used by FlyXc. -✨ _This workspace has been generated by [Nx, a Smart, fast and extensible build system.](https://nx.dev)_ ✨ - ## Support flyxc You can support the development of flyxc via the Buy me a Coffee platform @@ -36,3 +34,5 @@ You can support the development of flyxc via the Buy me a Coffee platform Buy Me A Coffee Any contribution is greatly appreciated! + +✨ _This workspace has been generated by [Nx, a Smart, fast and extensible build system.](https://nx.dev)_ ✨ diff --git a/libs/optimizer/README.md b/libs/optimizer/README.md index ae736845..398ddb02 100644 --- a/libs/optimizer/README.md +++ b/libs/optimizer/README.md @@ -2,24 +2,16 @@ ## Description -This library computes scores for flights using applicable rules of various XC leagues. +This library is a thin wrapper around [igc-xc-score](https://github.com/mmomtchev/igc-xc-score) by Momtchil Momtchev. -## Usage - -The `src/lib/optimizer.ts#optimize` function computes score of a given track given by a `ScoringTrack` for a given league known by it's `LeagueCode`. - -The `optimize` function is a generator function. +It is used to score flight tracks. -It takes an `OptimizationRequest` describing containing the track an some options. -It returns an `Iterator`. - -You should call the `next()` method of this iterator to get the current `IteratorResult`. -The `value` property of the `IteratorResult` gives the current `OptimizationResult` and the `done` property indicates whether the optimization is terminated. +## Usage -If the `done` property is false, you should call the `next()` method again to get a more optimal result. To get the best optimization, you should repeat the process until `done` is true. +The `getOptimizer` generator function computes score of a track. -See an example in `optimizer.spec.ts#expectOptimizationIsAsExpected` +The supported league rules are exposed in `scoringRuleNames`. ## Running unit tests From 64750372b7af531c3c8349791846d2f8e906dbdd Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 3 Jun 2024 21:52:41 +0200 Subject: [PATCH 13/20] add worker --- .../src/app/components/2d/path-element.ts | 51 ++++++++++++++----- apps/fxc-front/src/app/logic/score/scorer.ts | 1 + apps/fxc-front/src/app/workers/optimizer.ts | 26 ++++++++++ libs/optimizer/src/lib/optimizer.spec.ts | 28 ++++++---- libs/optimizer/src/lib/optimizer.ts | 33 +++++------- 5 files changed, 97 insertions(+), 42 deletions(-) create mode 100644 apps/fxc-front/src/app/workers/optimizer.ts diff --git a/apps/fxc-front/src/app/components/2d/path-element.ts b/apps/fxc-front/src/app/components/2d/path-element.ts index 74600460..82004401 100644 --- a/apps/fxc-front/src/app/components/2d/path-element.ts +++ b/apps/fxc-front/src/app/components/2d/path-element.ts @@ -19,9 +19,11 @@ import { setDistance, setEnabled, setRoute, setScore } from '../../redux/planner import type { RootState } from '../../redux/store'; import { store } from '../../redux/store'; import type { PlannerElement } from './planner-element'; -import { CircuitType, getOptimizer } from '@flyxc/optimizer'; +import { CircuitType, type ScoringResult } from '@flyxc/optimizer'; import { getScoringRuleName } from '../../logic/score/league/leagues'; import type { LeagueCode } from '../../logic/score/league/leagues'; +import ScoringWorker from '../../workers/optimizer?worker'; +import type { Request as WorkerRequest, Response as WorkerResponse } from '../../workers/optimizer'; // Route color by circuit type. const ROUTE_STROKE_COLORS = { @@ -63,6 +65,8 @@ export class PathElement extends connect(store)(LitElement) { private closingSector?: ClosingSector; private faiSectors?: FaiSectors; private plannerElement?: PlannerElement; + private scoringRequestId = 0; + private scoringWorker?: Worker; stateChanged(state: RootState): void { this.league = state.planner.league; @@ -198,24 +202,50 @@ export class PathElement extends connect(store)(LitElement) { if (!line || line.getPath().getLength() < 2 || this.doNotSyncState) { return; } - store.dispatch(setDistance(google.maps.geometry.spherical.computeLength(line.getPath()))); const points = this.getPathPoints(); - const score = this.computeScore(points); + + if (!this.scoringWorker) { + this.scoringWorker = new ScoringWorker(); + this.scoringWorker.onmessage = (msg: MessageEvent) => { + if (msg.data.id == this.scoringRequestId) { + this.optimizerCallback(this.toScore(msg.data.response)); + } + }; + } + + const request: WorkerRequest = { + request: { + track: { + points: points.map((point, i) => ({ ...point, alt: 0, timeSec: i * 60 })), + }, + ruleName: getScoringRuleName(this.league), + }, + id: ++this.scoringRequestId, + }; + + this.scoringWorker.postMessage(request); + } + + private optimizerCallback(score: Score): void { + store.dispatch(setDistance(score.distanceM)); store.dispatch(setScore(score)); - let optimizedPath = score.indexes.map((index) => new google.maps.LatLng(points[index].lat, points[index].lon)); + // TODO: add more info in the result + const points = this.getPathPoints(); + + let path = score.indexes.map((index) => new google.maps.LatLng(points[index].lat, points[index].lon)); if (score.circuit == CircuitType.FlatTriangle || score.circuit == CircuitType.FaiTriangle) { - optimizedPath = [optimizedPath[1], optimizedPath[2], optimizedPath[3], optimizedPath[1]]; + path = [path[1], path[2], path[3], path[1]]; } else if (score.circuit == CircuitType.OutAndReturn) { - optimizedPath = [optimizedPath[1], optimizedPath[2]]; + path = [path[1], path[2]]; } this.optimizedLine ??= new google.maps.Polyline(); this.optimizedLine.setOptions({ map: this.map, - path: optimizedPath, + path, strokeColor: ROUTE_STROKE_COLORS[score.circuit], strokeOpacity: 0.8, strokeWeight: 3, @@ -252,12 +282,7 @@ export class PathElement extends connect(store)(LitElement) { this.postScoreToHost(score); } - private computeScore(points: LatLon[]): Score { - // TODO: limit the processing time ? - const result = getOptimizer( - { track: { points: points.map((point, i) => ({ ...point, alt: 0, timeSec: i * 60 })) } }, - getScoringRuleName(this.league), - ).next().value; + private toScore(result: ScoringResult): Score { return new Score({ circuit: result.circuit, distanceM: result.lengthKm * 1000, diff --git a/apps/fxc-front/src/app/logic/score/scorer.ts b/apps/fxc-front/src/app/logic/score/scorer.ts index ff74b5dd..96718921 100644 --- a/apps/fxc-front/src/app/logic/score/scorer.ts +++ b/apps/fxc-front/src/app/logic/score/scorer.ts @@ -5,6 +5,7 @@ export class Score { indexes: number[]; multiplier: number; circuit: CircuitType; + // TODO: can we use 0 instead of null closingRadiusM: number | null; points: number; diff --git a/apps/fxc-front/src/app/workers/optimizer.ts b/apps/fxc-front/src/app/workers/optimizer.ts new file mode 100644 index 00000000..7d521893 --- /dev/null +++ b/apps/fxc-front/src/app/workers/optimizer.ts @@ -0,0 +1,26 @@ +import type { ScoringRequest, ScoringResult } from '@flyxc/optimizer'; +import { getOptimizer } from '@flyxc/optimizer'; + +export interface Request { + request: ScoringRequest; + id?: number; +} + +export interface Response { + response: ScoringResult; + id?: number; +} + +addEventListener('message', (event: MessageEvent) => { + const { request, id } = event.data; + const optimizer = getOptimizer(request); + let result: IteratorResult; + do { + result = optimizer.next(); + } while (!result.done); + + postMessage({ + response: result.value, + id, + } satisfies Response); +}); diff --git a/libs/optimizer/src/lib/optimizer.spec.ts b/libs/optimizer/src/lib/optimizer.spec.ts index 2d708c8f..b2ff6790 100644 --- a/libs/optimizer/src/lib/optimizer.spec.ts +++ b/libs/optimizer/src/lib/optimizer.spec.ts @@ -12,8 +12,9 @@ describe('optimizer', () => { it('Scores an empty request with a score of 0', () => { const request = { track: { points: [] }, + ruleName, }; - const result = optimize(request, ruleName); + const result = optimize(request); expect(result).toMatchObject({ score: 0, lengthKm: 0, @@ -29,11 +30,12 @@ describe('optimizer', () => { const request = { track: createSegments({ ...start, alt: 0, timeSec: 0 }, { ...end, alt: 0, timeSec: 60 }, segmentsPerBranch), + ruleName, }; const multiplier = getFreeDistanceMultiplier(ruleName); const distanceKm = getPreciseDistance(start, end) / 1000; - expect(optimize(request, ruleName)).toMatchObject({ + expect(optimize(request)).toMatchObject({ score: expect.closeTo(distanceKm * multiplier, 1), lengthKm: expect.closeTo(distanceKm, 1), multiplier, @@ -52,11 +54,12 @@ describe('optimizer', () => { createSegments({ ...start, alt: 0, timeSec: 0 }, { ...tp, alt: 0, timeSec: 60 }, segmentsPerBranch), createSegments({ ...tp, alt: 0, timeSec: 60 }, { ...end, alt: 0, timeSec: 120 }, segmentsPerBranch), ), + ruleName, }; const distanceKm = (getPreciseDistance(start, tp) + getPreciseDistance(tp, end)) / 1000; const multiplier = getFreeDistanceMultiplier(ruleName); - expect(optimize(request, ruleName)).toMatchObject({ + expect(optimize(request)).toMatchObject({ score: expect.closeTo(distanceKm * multiplier, 1), lengthKm: expect.closeTo(distanceKm, 1), multiplier, @@ -77,12 +80,13 @@ describe('optimizer', () => { createSegments({ ...tp1, alt: 0, timeSec: 60 }, { ...tp2, alt: 0, timeSec: 120 }, segmentsPerBranch), createSegments({ ...tp2, alt: 0, timeSec: 120 }, { ...end, alt: 0, timeSec: 180 }, segmentsPerBranch), ), + ruleName, }; const distanceKm = (getPreciseDistance(start, tp1) + getPreciseDistance(tp1, tp2) + getPreciseDistance(tp2, end)) / 1000; const multiplier = getFreeDistanceMultiplier(ruleName); - expect(optimize(request, ruleName)).toMatchObject({ + expect(optimize(request)).toMatchObject({ score: expect.closeTo(distanceKm * multiplier, 1), lengthKm: expect.closeTo(distanceKm, 1), multiplier, @@ -105,6 +109,7 @@ describe('optimizer', () => { createSegments({ ...tp2, alt: 0, timeSec: 120 }, { ...tp3, alt: 0, timeSec: 180 }, segmentsPerBranch), createSegments({ ...tp3, alt: 0, timeSec: 180 }, { ...end, alt: 0, timeSec: 240 }, segmentsPerBranch), ), + ruleName, }; const distanceKm = @@ -114,7 +119,7 @@ describe('optimizer', () => { getPreciseDistance(tp3, end)) / 1000; const multiplier = getFreeDistanceMultiplier(ruleName); - expect(optimize(request, ruleName)).toMatchObject({ + expect(optimize(request)).toMatchObject({ score: expect.closeTo(distanceKm * multiplier, 1), lengthKm: expect.closeTo(distanceKm, 1), multiplier, @@ -134,12 +139,13 @@ describe('optimizer', () => { createSegments({ ...tp2, alt: 0, timeSec: 60 }, { ...tp3, alt: 0, timeSec: 120 }, segmentsPerBranch), createSegments({ ...tp3, alt: 0, timeSec: 120 }, { ...tp1, alt: 0, timeSec: 180 }, segmentsPerBranch), ), + ruleName, }; const distanceKm = (getPreciseDistance(tp1, tp2) + getPreciseDistance(tp2, tp3) + getPreciseDistance(tp3, tp1)) / 1000; const multiplier = getFlatTriangleMultiplier(ruleName); - expect(optimize(request, ruleName)).toMatchObject({ + expect(optimize(request)).toMatchObject({ score: expect.closeTo(distanceKm * multiplier, 1), lengthKm: expect.closeTo(distanceKm, 1), multiplier, @@ -164,12 +170,13 @@ describe('optimizer', () => { createSegments({ ...tp2, alt: 0, timeSec: 60 }, { ...tp3, alt: 0, timeSec: 120 }, segmentsPerBranch), createSegments({ ...tp3, alt: 0, timeSec: 120 }, { ...tp1, alt: 0, timeSec: 180 }, segmentsPerBranch), ), + ruleName, }; const distanceKm = (getPreciseDistance(tp1, tp2) + getPreciseDistance(tp2, tp3) + getPreciseDistance(tp3, tp1)) / 1000; const multiplier = getFaiTriangleMultiplier(ruleName); - expect(optimize(request, ruleName)).toMatchObject({ + expect(optimize(request)).toMatchObject({ score: expect.closeTo(distanceKm * multiplier, 1), lengthKm: expect.closeTo(distanceKm, 1), multiplier, @@ -197,13 +204,14 @@ describe('optimizer', () => { createSegments({ ...tp2, alt: 0, timeSec: 60 }, { ...tp3, alt: 0, timeSec: 120 }, 10), createSegments({ ...tp3, alt: 0, timeSec: 120 }, { ...tp1, alt: 0, timeSec: 180 }, 10), ), + ruleName: 'FFVL', maxNumCycles: 1, }; const distanceKm = (getPreciseDistance(tp1, tp2) + getPreciseDistance(tp2, tp3) + getPreciseDistance(tp3, tp1)) / 1000; const multiplier = getFaiTriangleMultiplier('FFVL'); - expect(optimize(request, 'FFVL')).toMatchObject({ + expect(optimize(request)).toMatchObject({ score: expect.closeTo(distanceKm * multiplier, 1), lengthKm: expect.closeTo(distanceKm, 1), multiplier, @@ -213,8 +221,8 @@ describe('optimizer', () => { }); }); -function optimize(request: ScoringRequest, ruleName: ScoringRuleName): ScoringResult { - const optimizer = getOptimizer(request, ruleName); +function optimize(request: ScoringRequest): ScoringResult { + const optimizer = getOptimizer(request); let result: IteratorResult; do { result = optimizer.next(); diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index 740f3f0b..f184c050 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -23,15 +23,10 @@ export interface ScoringTrack { export interface ScoringRequest { track: ScoringTrack; - /** - * Maximum duration for an optimization round trip. - * If undefined, calculation duration is unbounded. - */ + ruleName: ScoringRuleName; + /** Maximum cycle duration. Unbounded when not provided */ maxCycleDurationMs?: number; - /** - * Maximum number of iterations allowed for an optimization round trip. - * If undefined, number of allowed iterations is unbounded - */ + /** Maximum number of cycles. Unbounded when not provided */ maxNumCycles?: number; } @@ -86,11 +81,8 @@ export interface ScoringResult { * @param ruleName The ScoringRules to use. * @returns an Iterator of OptimizationResult */ -export function* getOptimizer( - request: ScoringRequest, - ruleName: ScoringRuleName, -): Iterator { - if (request.track.points.length == 0) { +export function* getOptimizer(request: ScoringRequest): Iterator { + if (request.track.points.length === 0) { // console.warn('Empty track received in optimization request. Returns a 0 score'); return { score: 0, @@ -100,18 +92,21 @@ export function* getOptimizer( optimal: true, }; } - const originalTrack = request.track; - const flight = toIgcFile(appendPointsIfNeeded(originalTrack, MIN_IGC_XC_SCORE_POINTS)); - const solverScoringRules = scoringRules.get(ruleName); + const { track } = request; + const flight = toIgcFile(appendPointsIfNeeded(track, MIN_IGC_XC_SCORE_POINTS)); + const solverScoringRules = scoringRules.get(request.ruleName); + if (solverScoringRules == null) { + throw new Error(`Unknown scoring rule: ${request.ruleName}`); + } const options = toSolverOptions(request); - const solutionIterator = solver(flight, solverScoringRules || {}, options); + const solutionIterator = solver(flight, solverScoringRules, options); while (true) { const solution = solutionIterator.next(); if (solution.done) { // console.debug('solution', JSON.stringify(solution.value, undefined, 2)); - return toOptimizationResult(solution.value, originalTrack); + return toOptimizationResult(solution.value, track); } - yield toOptimizationResult(solution.value, originalTrack); + yield toOptimizationResult(solution.value, track); } } From 1e6abb7cdafc4de48cd931fc08b2c7e24054236b Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 3 Jun 2024 22:49:47 +0200 Subject: [PATCH 14/20] Add more info in the result --- .../src/app/components/2d/map-element.ts | 2 +- .../src/app/components/2d/path-element.ts | 25 +++---- libs/optimizer/src/lib/optimizer.ts | 70 +++++++++++-------- 3 files changed, 51 insertions(+), 46 deletions(-) diff --git a/apps/fxc-front/src/app/components/2d/map-element.ts b/apps/fxc-front/src/app/components/2d/map-element.ts index a1f55e45..56936ee8 100644 --- a/apps/fxc-front/src/app/components/2d/map-element.ts +++ b/apps/fxc-front/src/app/components/2d/map-element.ts @@ -332,7 +332,7 @@ export class MapElement extends connect(store)(LitElement) { this.pointerEventId = undefined; this.freeDrawPath = ''; store.dispatch(setIsFreeDrawing(false)); - this.pathPoints = simplify(this.pathPoints, 30); + this.pathPoints = simplify(this.pathPoints, 15); let encodedRoute = ''; if (this.pathPoints.length >= 2 && this.map) { const proj = this.map.getProjection() as google.maps.Projection; diff --git a/apps/fxc-front/src/app/components/2d/path-element.ts b/apps/fxc-front/src/app/components/2d/path-element.ts index 82004401..45895a73 100644 --- a/apps/fxc-front/src/app/components/2d/path-element.ts +++ b/apps/fxc-front/src/app/components/2d/path-element.ts @@ -209,7 +209,7 @@ export class PathElement extends connect(store)(LitElement) { this.scoringWorker = new ScoringWorker(); this.scoringWorker.onmessage = (msg: MessageEvent) => { if (msg.data.id == this.scoringRequestId) { - this.optimizerCallback(this.toScore(msg.data.response)); + this.optimizerCallback(msg.data.response); } }; } @@ -227,19 +227,14 @@ export class PathElement extends connect(store)(LitElement) { this.scoringWorker.postMessage(request); } - private optimizerCallback(score: Score): void { + private optimizerCallback(result: ScoringResult): void { + const score = this.toScore(result); store.dispatch(setDistance(score.distanceM)); store.dispatch(setScore(score)); - // TODO: add more info in the result - const points = this.getPathPoints(); - - let path = score.indexes.map((index) => new google.maps.LatLng(points[index].lat, points[index].lon)); - if (score.circuit == CircuitType.FlatTriangle || score.circuit == CircuitType.FaiTriangle) { - path = [path[1], path[2], path[3], path[1]]; - } else if (score.circuit == CircuitType.OutAndReturn) { - path = [path[1], path[2]]; - } + let path = [result.startPoint, ...result.turnpoints, result.endPoint] + .filter((p) => p != null) + .map((p) => ({ lat: p!.lat, lng: p!.lon })); this.optimizedLine ??= new google.maps.Polyline(); @@ -257,9 +252,8 @@ export class PathElement extends connect(store)(LitElement) { this.closingSector.addListener('rightclick', (e) => this.appendToPath(e.latLng)); } - if (score.closingRadiusM) { - const center = points[score.indexes[0]]; - this.closingSector.center = center; + if (score.closingRadiusM && result.startPoint) { + this.closingSector.center = result.startPoint; this.closingSector.radius = score.closingRadiusM; this.closingSector.update(); this.closingSector.setMap(this.map); @@ -272,8 +266,7 @@ export class PathElement extends connect(store)(LitElement) { this.faiSectors.addListeners('rightclick', (e) => this.appendToPath(e.latLng)); } if (score.circuit == CircuitType.FlatTriangle || score.circuit == CircuitType.FaiTriangle) { - const faiPoints = score.indexes.slice(1, 4).map((i) => points[i]); - this.faiSectors.update(faiPoints); + this.faiSectors.update(result.turnpoints); this.faiSectors.setMap(this.map); } else { this.faiSectors.setMap(null); diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index f184c050..db13a969 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -1,6 +1,6 @@ // TODO: all console logs are commented out. In the future, we should use a logging library -import type { Solution } from 'igc-xc-score'; +import type { Point, Solution } from 'igc-xc-score'; import { solver } from 'igc-xc-score'; import type { BRecord, IGCFile } from 'igc-parser'; import type { ScoringRuleName } from './scoring-rules'; @@ -10,10 +10,13 @@ import { scoringRules } from './scoring-rules'; // See this issue https://github.com/mmomtchev/igc-xc-score/issues/231 const MIN_IGC_XC_SCORE_POINTS = 5; -export interface LatLonAltTime { - alt: number; +export interface LatLon { lat: number; lon: number; +} + +export interface LatLonAltTime extends LatLon { + alt: number; timeSec: number; } @@ -37,37 +40,31 @@ export enum CircuitType { OutAndReturn = 'Out and return', } +export interface Leg { + name: string; + lengthKm: number; + start: LatLon; + end: LatLon; +} export interface ScoringResult { - /** - * The score for the track in the given league - */ + // The score for the track in the given league score: number; - /** - * The length of the optimized track in kms - */ + // The length of the optimized track in kms lengthKm: number; - /** - * TODO: we probably do not need all 3 of score, lengthKm, and multiplier. - * Multiplier for computing score. score = lengthKm * multiplier - */ + // Multiplier for computing score. score = lengthKm * multiplier multiplier: number; - /** - * Type of the optimized track - */ circuit?: CircuitType; - /** - * If applicable, Distance in m for closing the circuit - */ + // If applicable, Distance in m for closing the circuit closingRadiusM?: number; - /** - * Indices of solutions points in the request - */ + // Indices of solutions points in the request solutionIndices: number[]; - /** - * Whether the result is optimal. - * If not the optimizer can be cycled again to get a more accurate solution. - */ + // Whether the result is optimal. + //If not the optimizer can be cycled again to get a more accurate solution. optimal: boolean; + startPoint?: LatLon; + endPoint?: LatLon; + legs: Leg[]; + turnpoints: LatLon[]; } /** @@ -90,6 +87,8 @@ export function* getOptimizer(request: ScoringRequest): Iterator ({ + name, + lengthKm: d, + start: pointToLatTon(start), + end: pointToLatTon(finish), + })), + turnpoints: (solution.scoreInfo?.tp ?? []).map((point) => pointToLatTon(point)), }; } +function pointToLatTon(point: Point): LatLon { + return { lat: point.y, lon: point.x }; +} + function getClosingRadiusM(solution: Solution): number | undefined { const closingDistance = solution.scoreInfo?.cp?.d; From 800f62801eebff2b45667a74202e4b3448ff016c Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Tue, 4 Jun 2024 06:20:55 +0200 Subject: [PATCH 15/20] typo --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 65254868..54a0fd9d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ ## Project setup - run `npm install` -- add default keys definitions +- add default key definitions - `cp apps/fxc-front/src/app/keys.ts.dist apps/fxc-front/src/app/keys.ts` - `cp libs/common/src/lib/keys.ts.dist libs/common/src/lib/keys.ts` From c0447aa0a9b62a9a2aa85db4231e4c4b11b9c573 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Tue, 4 Jun 2024 07:24:23 +0200 Subject: [PATCH 16/20] fixes --- .../src/app/components/2d/path-element.ts | 12 ++++++---- apps/fxc-front/src/app/gm/closing-sector.ts | 17 +++++--------- apps/fxc-front/src/app/logic/score/scorer.ts | 5 ++--- libs/optimizer/src/lib/optimizer.ts | 22 +++++++++++-------- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/apps/fxc-front/src/app/components/2d/path-element.ts b/apps/fxc-front/src/app/components/2d/path-element.ts index 45895a73..b03dbfc9 100644 --- a/apps/fxc-front/src/app/components/2d/path-element.ts +++ b/apps/fxc-front/src/app/components/2d/path-element.ts @@ -232,10 +232,14 @@ export class PathElement extends connect(store)(LitElement) { store.dispatch(setDistance(score.distanceM)); store.dispatch(setScore(score)); - let path = [result.startPoint, ...result.turnpoints, result.endPoint] + const path = [result.startPoint, ...result.turnpoints, result.endPoint] .filter((p) => p != null) .map((p) => ({ lat: p!.lat, lng: p!.lon })); + if (result.circuit != CircuitType.OpenDistance) { + path.push(path[0]); + } + this.optimizedLine ??= new google.maps.Polyline(); this.optimizedLine.setOptions({ @@ -252,8 +256,8 @@ export class PathElement extends connect(store)(LitElement) { this.closingSector.addListener('rightclick', (e) => this.appendToPath(e.latLng)); } - if (score.closingRadiusM && result.startPoint) { - this.closingSector.center = result.startPoint; + if (result.closingPoints) { + this.closingSector.center = result.closingPoints.in; this.closingSector.radius = score.closingRadiusM; this.closingSector.update(); this.closingSector.setMap(this.map); @@ -280,7 +284,7 @@ export class PathElement extends connect(store)(LitElement) { circuit: result.circuit, distanceM: result.lengthKm * 1000, multiplier: result.multiplier, - closingRadiusM: result.closingRadiusM ? result.closingRadiusM * 1000 : null, + closingRadiusM: (result.closingRadiusM ?? 0) * 1000, indexes: result.solutionIndices, points: result.score, }); diff --git a/apps/fxc-front/src/app/gm/closing-sector.ts b/apps/fxc-front/src/app/gm/closing-sector.ts index 799a050d..08c92f7c 100644 --- a/apps/fxc-front/src/app/gm/closing-sector.ts +++ b/apps/fxc-front/src/app/gm/closing-sector.ts @@ -1,12 +1,10 @@ -import { computeDestinationPoint } from 'geolib'; - export class ClosingSector { center: { lat: number; lon: number } | null = null; radius: number | null = null; - poly: google.maps.Polygon; + circle: google.maps.Circle; constructor() { - this.poly = new google.maps.Polygon({ + this.circle = new google.maps.Circle({ fillColor: '#ffff00', fillOpacity: 0.3, strokeColor: '#ffff00', @@ -17,21 +15,18 @@ export class ClosingSector { } setMap(map?: google.maps.Map | null): void { - this.poly.setMap(map ?? null); + this.circle.setMap(map ?? null); } addListener(name: string, handler: (...args: any[]) => void): google.maps.MapsEventListener { - return this.poly.addListener(name, handler); + return this.circle.addListener(name, handler); } update(): void { if (this.center == null || this.radius == null) { return; } - const path: { latitude: number; longitude: number }[] = [{ latitude: this.center.lat, longitude: this.center.lon }]; - for (let i = 0; i <= 360; i += 10) { - path.push(computeDestinationPoint(this.center, this.radius, i)); - } - this.poly.setPath(path.map(({ latitude, longitude }) => new google.maps.LatLng(latitude, longitude))); + this.circle.setCenter({ lat: this.center.lat, lng: this.center.lon }); + this.circle.setRadius(this.radius); } } diff --git a/apps/fxc-front/src/app/logic/score/scorer.ts b/apps/fxc-front/src/app/logic/score/scorer.ts index 96718921..a8c07fb4 100644 --- a/apps/fxc-front/src/app/logic/score/scorer.ts +++ b/apps/fxc-front/src/app/logic/score/scorer.ts @@ -5,8 +5,7 @@ export class Score { indexes: number[]; multiplier: number; circuit: CircuitType; - // TODO: can we use 0 instead of null - closingRadiusM: number | null; + closingRadiusM: number; points: number; constructor(score: Partial) { @@ -14,7 +13,7 @@ export class Score { this.indexes = score.indexes ?? []; this.multiplier = score.multiplier ?? 1; this.circuit = score.circuit ?? CircuitType.OpenDistance; - this.closingRadiusM = score.closingRadiusM ?? null; + this.closingRadiusM = score.closingRadiusM ?? 0; this.points = score.points ?? 0; } } diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index db13a969..844a8489 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -1,5 +1,3 @@ -// TODO: all console logs are commented out. In the future, we should use a logging library - import type { Point, Solution } from 'igc-xc-score'; import { solver } from 'igc-xc-score'; import type { BRecord, IGCFile } from 'igc-parser'; @@ -54,7 +52,6 @@ export interface ScoringResult { // Multiplier for computing score. score = lengthKm * multiplier multiplier: number; circuit?: CircuitType; - // If applicable, Distance in m for closing the circuit closingRadiusM?: number; // Indices of solutions points in the request solutionIndices: number[]; @@ -65,6 +62,10 @@ export interface ScoringResult { endPoint?: LatLon; legs: Leg[]; turnpoints: LatLon[]; + closingPoints?: { + in: LatLon; + out: LatLon; + }; } /** @@ -80,7 +81,6 @@ export interface ScoringResult { */ export function* getOptimizer(request: ScoringRequest): Iterator { if (request.track.points.length === 0) { - // console.warn('Empty track received in optimization request. Returns a 0 score'); return { score: 0, lengthKm: 0, @@ -102,7 +102,6 @@ export function* getOptimizer(request: ScoringRequest): Iterator pointToLatTon(point)), + closingPoints: solution.scoreInfo?.cp + ? { + in: pointToLatTon(solution.scoreInfo.cp.in), + out: pointToLatTon(solution.scoreInfo.cp.out), + } + : undefined, }; } @@ -227,7 +231,7 @@ function getClosingRadiusM(solution: Solution): number | undefined { return undefined; } -const circuitMapping = { +const circuitMapping: Readonly> = { od: CircuitType.OpenDistance, tri: CircuitType.FlatTriangle, fai: CircuitType.FaiTriangle, @@ -235,7 +239,7 @@ const circuitMapping = { }; function toCircuitType(code: string): CircuitType { - const type = circuitMapping[code as 'od' | 'tri' | 'fai' | 'oar']; + const type = circuitMapping[code]; if (type == null) { throw new Error(`Unknown type "${code}"`); } From 72680a854e3a2e1c684e252db47611ebe7958327 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Tue, 4 Jun 2024 07:45:27 +0200 Subject: [PATCH 17/20] no barrel --- libs/optimizer/src/index.ts | 3 --- libs/optimizer/src/lib/api.ts | 26 ++++++++++++++++++++++++ libs/optimizer/src/lib/optimizer.spec.ts | 5 ++--- libs/optimizer/src/lib/optimizer.ts | 10 ++------- libs/optimizer/src/lib/scoring-rules.ts | 20 ++---------------- 5 files changed, 32 insertions(+), 32 deletions(-) delete mode 100644 libs/optimizer/src/index.ts create mode 100644 libs/optimizer/src/lib/api.ts diff --git a/libs/optimizer/src/index.ts b/libs/optimizer/src/index.ts deleted file mode 100644 index 6c2c19f4..00000000 --- a/libs/optimizer/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { getOptimizer, CircuitType } from './lib/optimizer'; -export type { LatLonAltTime, ScoringTrack, ScoringResult, ScoringRequest } from './lib/optimizer'; -export type { ScoringRuleName, scoringRuleNames } from './lib/scoring-rules'; diff --git a/libs/optimizer/src/lib/api.ts b/libs/optimizer/src/lib/api.ts new file mode 100644 index 00000000..f0d8fb8f --- /dev/null +++ b/libs/optimizer/src/lib/api.ts @@ -0,0 +1,26 @@ +// Do not depend on igc-xc-score that pollutes the global namespace +// See https://github.com/mmomtchev/igc-xc-score/issues/234 + +export const scoringRuleNames = [ + 'CzechLocal', + 'CzechEurope', + 'CzechOutsideEurope', + 'FFVL', + 'Leonardo', + 'Norway', + 'UKClub', + 'UKInternational', + 'UKNational', + 'XContest', + 'XContestPPG', + 'WorldXC', +] as const; + +export enum CircuitType { + OpenDistance = 'Open distance', + FlatTriangle = 'Flat triangle', + FaiTriangle = 'Fai triangle', + OutAndReturn = 'Out and return', +} + +export type ScoringRuleName = (typeof scoringRuleNames)[number]; diff --git a/libs/optimizer/src/lib/optimizer.spec.ts b/libs/optimizer/src/lib/optimizer.spec.ts index b2ff6790..aae888c5 100644 --- a/libs/optimizer/src/lib/optimizer.spec.ts +++ b/libs/optimizer/src/lib/optimizer.spec.ts @@ -1,10 +1,9 @@ import type { ScoringRequest, ScoringResult } from './optimizer'; -import { CircuitType, getOptimizer } from './optimizer'; -import type { ScoringRuleName } from './scoring-rules'; -import { scoringRuleNames } from './scoring-rules'; +import { getOptimizer } from './optimizer'; import { computeDestinationPoint, getGreatCircleBearing, getPreciseDistance } from 'geolib'; import { createSegments } from './utils/create-segments'; import { mergeTracks } from './utils/merge-tracks'; +import { CircuitType, scoringRuleNames, type ScoringRuleName } from './api'; describe('optimizer', () => { scoringRuleNames.forEach((ruleName) => { diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index 844a8489..e9d126de 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -1,8 +1,9 @@ import type { Point, Solution } from 'igc-xc-score'; import { solver } from 'igc-xc-score'; import type { BRecord, IGCFile } from 'igc-parser'; -import type { ScoringRuleName } from './scoring-rules'; +import type { ScoringRuleName } from './api'; import { scoringRules } from './scoring-rules'; +import type { CircuitType } from './api'; // Minimum number of points in an igc-xc-score track. // See this issue https://github.com/mmomtchev/igc-xc-score/issues/231 @@ -31,13 +32,6 @@ export interface ScoringRequest { maxNumCycles?: number; } -export enum CircuitType { - OpenDistance = 'Open distance', - FlatTriangle = 'Flat triangle', - FaiTriangle = 'Fai triangle', - OutAndReturn = 'Out and return', -} - export interface Leg { name: string; lengthKm: number; diff --git a/libs/optimizer/src/lib/scoring-rules.ts b/libs/optimizer/src/lib/scoring-rules.ts index 8cc5932e..1721e78a 100644 --- a/libs/optimizer/src/lib/scoring-rules.ts +++ b/libs/optimizer/src/lib/scoring-rules.ts @@ -1,24 +1,8 @@ import * as igcXcScore from 'igc-xc-score'; - -export const scoringRuleNames = [ - 'CzechLocal', - 'CzechEurope', - 'CzechOutsideEurope', - 'FFVL', - 'Leonardo', - 'Norway', - 'UKClub', - 'UKInternational', - 'UKNational', - 'XContest', - 'XContestPPG', - 'WorldXC', -] as const; - -export type ScoringRuleName = (typeof scoringRuleNames)[number]; +import type { ScoringRuleName } from './api'; // TODO: Export the rules from igc-xc-score -const scoringBaseModel = igcXcScore.scoringRules['XContest']; +const scoringBaseModel = igcXcScore.scoringRules.XContest; const openDistance = scoringBaseModel[0]; const freeTriangle = scoringBaseModel[1]; const faiTriangle = scoringBaseModel[2]; From 5068defab6101d147d03bb0862935c3e478e0c85 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Tue, 4 Jun 2024 08:37:54 +0200 Subject: [PATCH 18/20] step --- .verdaccio/config.yml | 28 ++++++ apps/fxc-front/project.json | 1 + .../src/app/components/2d/path-element.ts | 2 +- libs/optimizer/package-lock.json | 97 +++++++++++++++++++ libs/optimizer/package.json | 12 +++ libs/optimizer/project.json | 12 +++ libs/optimizer/src/lib/optimizer.ts | 2 +- tsconfig.base.json | 2 +- 8 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 .verdaccio/config.yml create mode 100644 libs/optimizer/package-lock.json create mode 100644 libs/optimizer/package.json diff --git a/.verdaccio/config.yml b/.verdaccio/config.yml new file mode 100644 index 00000000..a007fe82 --- /dev/null +++ b/.verdaccio/config.yml @@ -0,0 +1,28 @@ +# path to a directory with all packages +storage: ../tmp/local-registry/storage + +# a list of other known repositories we can talk to +uplinks: + npmjs: + url: https://registry.npmjs.org/ + maxage: 60m + +packages: + '**': + # give all users (including non-authenticated users) full access + # because it is a local registry + access: $all + publish: $all + unpublish: $all + + # if package is not available locally, proxy requests to npm registry + proxy: npmjs + +# log settings +logs: + type: stdout + format: pretty + level: warn + +publish: + allow_offline: true # set offline to true to allow publish offline diff --git a/apps/fxc-front/project.json b/apps/fxc-front/project.json index 601ae14d..02618c12 100644 --- a/apps/fxc-front/project.json +++ b/apps/fxc-front/project.json @@ -7,6 +7,7 @@ "targets": { "build": { "executor": "@nx/vite:build", + "dependsOn": ["optimizer"], "outputs": ["{options.outputPath}"], "defaultConfiguration": "production", "options": { diff --git a/apps/fxc-front/src/app/components/2d/path-element.ts b/apps/fxc-front/src/app/components/2d/path-element.ts index b03dbfc9..b8bc8811 100644 --- a/apps/fxc-front/src/app/components/2d/path-element.ts +++ b/apps/fxc-front/src/app/components/2d/path-element.ts @@ -19,11 +19,11 @@ import { setDistance, setEnabled, setRoute, setScore } from '../../redux/planner import type { RootState } from '../../redux/store'; import { store } from '../../redux/store'; import type { PlannerElement } from './planner-element'; -import { CircuitType, type ScoringResult } from '@flyxc/optimizer'; import { getScoringRuleName } from '../../logic/score/league/leagues'; import type { LeagueCode } from '../../logic/score/league/leagues'; import ScoringWorker from '../../workers/optimizer?worker'; import type { Request as WorkerRequest, Response as WorkerResponse } from '../../workers/optimizer'; +import { CircuitType } from '@flyxc/optimizer/src/api'; // Route color by circuit type. const ROUTE_STROKE_COLORS = { diff --git a/libs/optimizer/package-lock.json b/libs/optimizer/package-lock.json new file mode 100644 index 00000000..793a3932 --- /dev/null +++ b/libs/optimizer/package-lock.json @@ -0,0 +1,97 @@ +{ + "name": "@flyxc/optimizer", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@flyxc/optimizer", + "version": "0.0.1", + "dependencies": { + "igc-parser": "^1.1.0", + "igc-xc-score": "^1.7.0", + "tslib": "^2.3.0" + } + }, + "node_modules/collections": { + "version": "5.1.13", + "resolved": "https://registry.npmjs.org/collections/-/collections-5.1.13.tgz", + "integrity": "sha512-SCb6Qd+d3Z02corWQ7/mqXiXeeTdHvkP6TeFSYfGYdCFp1WrjSNZ3j6y8Y3T/7osGEe0iOcU2g1d346l99m4Lg==", + "dependencies": { + "weak-map": "~1.0.x" + } + }, + "node_modules/flatbush": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/flatbush/-/flatbush-4.4.0.tgz", + "integrity": "sha512-cf6G+sfy/+/FLH7Ls1URQ5GCRlXgwgqUZiEsMNrMZqb3Us3EkKmzUlKbnyoBy/4wI4oLJ+8cyCQoKJIVm92Fmg==", + "dependencies": { + "flatqueue": "^2.0.3" + } + }, + "node_modules/flatqueue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/flatqueue/-/flatqueue-2.0.3.tgz", + "integrity": "sha512-RZCWZNkmxzUOh8jqEcEGZCycb3B8KAfpPwg3H//cURasunYxsg1eIvE+QDSjX+ZPHTIVfINfK1aLTrVKKO0i4g==", + "engines": { + "node": ">= 12.17.0" + } + }, + "node_modules/flight-recorder-manufacturers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flight-recorder-manufacturers/-/flight-recorder-manufacturers-2.0.0.tgz", + "integrity": "sha512-FhSY7XslPkhYGdBBVRLLExoKqiLWbKuxPEx3O3a443hp8VOrcvE+ibibigVplQbaNipVG3pSPTZPTFJPIfcO8Q==", + "engines": { + "node": ">=12" + } + }, + "node_modules/igc-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/igc-parser/-/igc-parser-1.1.0.tgz", + "integrity": "sha512-CJGWiCcCCxNSI3Pt0zbllHNekEp2NOVCgDysg5/7FuW/uXUUDiW+AcZWSwRwvtRQxnYf+Sn7mQmYKLWQfVSATA==", + "dependencies": { + "flight-recorder-manufacturers": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/igc-xc-score": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/igc-xc-score/-/igc-xc-score-1.7.0.tgz", + "integrity": "sha512-49UQM9mbXjTo2mmeRYIq0vszShw8bg8TKhTU2XGwBCmSk0ojJFACajeZKSB0dT8u3F6p+7ap1oRv17g22Xh3PA==", + "dependencies": { + "collections": "^5.1.13", + "flatbush": "^4.0.0", + "igc-parser": "^1.1.0", + "rbush": "^3.0.1" + }, + "bin": { + "igc-xc-score": "dist/igc-xc-score.cjs" + } + }, + "node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + }, + "node_modules/rbush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", + "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", + "dependencies": { + "quickselect": "^2.0.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/weak-map": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.8.tgz", + "integrity": "sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw==" + } + } +} diff --git a/libs/optimizer/package.json b/libs/optimizer/package.json new file mode 100644 index 00000000..b9e8cdbb --- /dev/null +++ b/libs/optimizer/package.json @@ -0,0 +1,12 @@ +{ + "name": "@flyxc/optimizer", + "version": "0.0.1", + "dependencies": { + "igc-parser": "^1.1.0", + "igc-xc-score": "^1.7.0", + "tslib": "^2.3.0" + }, + "type": "commonjs", + "main": "./src/index.js", + "typings": "./src/index.d.ts" +} diff --git a/libs/optimizer/project.json b/libs/optimizer/project.json index b2bb5399..62289a47 100644 --- a/libs/optimizer/project.json +++ b/libs/optimizer/project.json @@ -4,6 +4,18 @@ "sourceRoot": "libs/optimizer/src", "projectType": "library", "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/libs/optimizer", + "main": "./src/lib/optimizer.ts", + "additionalEntryPoints": ["libs/optimizer/src/lib/api.ts", "libs/optimizer/src/lib/scoring-rules.ts"], + "generateExportsField": true, + "tsConfig": "libs/optimizer/tsconfig.lib.json", + "assets": ["libs/optimizer/*.md"] + } + }, "lint": { "executor": "@nx/eslint:lint", "outputs": ["{options.outputFile}"] diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index e9d126de..ae471491 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -3,7 +3,7 @@ import { solver } from 'igc-xc-score'; import type { BRecord, IGCFile } from 'igc-parser'; import type { ScoringRuleName } from './api'; import { scoringRules } from './scoring-rules'; -import type { CircuitType } from './api'; +import { CircuitType } from './api'; // Minimum number of points in an igc-xc-score track. // See this issue https://github.com/mmomtchev/igc-xc-score/issues/231 diff --git a/tsconfig.base.json b/tsconfig.base.json index fec0118f..476cc855 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -18,7 +18,7 @@ "paths": { "@flyxc/common": ["libs/common/src/index.ts"], "@flyxc/common-node": ["libs/common-node/src/index.ts"], - "@flyxc/optimizer": ["libs/optimizer/src/index.ts"], + "@flyxc/optimizer/*": ["libs/optimizer/src/*"], "@vaadin/dom": ["libs/vaadin-dom/src/index.ts"], "@vaadin/nodom": ["libs/vaadin-nodom/src/index.ts"] } From 6f9567f0ab0dc82f2889b093deeb47197d3e78fc Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Tue, 4 Jun 2024 10:30:49 +0200 Subject: [PATCH 19/20] fixes --- .../src/app/components/2d/path-element.ts | 3 +- .../src/app/logic/score/league/leagues.ts | 2 +- apps/fxc-front/src/app/logic/score/scorer.ts | 2 +- apps/fxc-front/src/app/workers/optimizer.ts | 4 +- libs/optimizer/package.json | 2 +- libs/optimizer/project.json | 8 +- libs/optimizer/src/index.ts | 2 + libs/optimizer/src/lib/scoring-rules.ts | 2 +- libs/optimizer/tsconfig.json | 11 +- package-lock.json | 2094 +++++++++++++++-- 10 files changed, 1905 insertions(+), 225 deletions(-) create mode 100644 libs/optimizer/src/index.ts diff --git a/apps/fxc-front/src/app/components/2d/path-element.ts b/apps/fxc-front/src/app/components/2d/path-element.ts index b8bc8811..8eef9498 100644 --- a/apps/fxc-front/src/app/components/2d/path-element.ts +++ b/apps/fxc-front/src/app/components/2d/path-element.ts @@ -23,7 +23,8 @@ import { getScoringRuleName } from '../../logic/score/league/leagues'; import type { LeagueCode } from '../../logic/score/league/leagues'; import ScoringWorker from '../../workers/optimizer?worker'; import type { Request as WorkerRequest, Response as WorkerResponse } from '../../workers/optimizer'; -import { CircuitType } from '@flyxc/optimizer/src/api'; +import { CircuitType } from '@flyxc/optimizer/lib/api'; +import type { ScoringResult } from '@flyxc/optimizer/lib/optimizer'; // Route color by circuit type. const ROUTE_STROKE_COLORS = { diff --git a/apps/fxc-front/src/app/logic/score/league/leagues.ts b/apps/fxc-front/src/app/logic/score/league/leagues.ts index 56ff2491..09eb48ad 100644 --- a/apps/fxc-front/src/app/logic/score/league/leagues.ts +++ b/apps/fxc-front/src/app/logic/score/league/leagues.ts @@ -1,4 +1,4 @@ -import type { ScoringRuleName } from '@flyxc/optimizer'; +import type { ScoringRuleName } from '@flyxc/optimizer/lib/api'; export const LEAGUE_CODES = [ 'czl', diff --git a/apps/fxc-front/src/app/logic/score/scorer.ts b/apps/fxc-front/src/app/logic/score/scorer.ts index a8c07fb4..7fb6fb9a 100644 --- a/apps/fxc-front/src/app/logic/score/scorer.ts +++ b/apps/fxc-front/src/app/logic/score/scorer.ts @@ -1,4 +1,4 @@ -import { CircuitType } from '@flyxc/optimizer'; +import { CircuitType } from '@flyxc/optimizer/lib/api'; export class Score { distanceM: number; diff --git a/apps/fxc-front/src/app/workers/optimizer.ts b/apps/fxc-front/src/app/workers/optimizer.ts index 7d521893..dcec1eb6 100644 --- a/apps/fxc-front/src/app/workers/optimizer.ts +++ b/apps/fxc-front/src/app/workers/optimizer.ts @@ -1,5 +1,5 @@ -import type { ScoringRequest, ScoringResult } from '@flyxc/optimizer'; -import { getOptimizer } from '@flyxc/optimizer'; +import type { ScoringRequest, ScoringResult } from '@flyxc/optimizer/lib/optimizer'; +import { getOptimizer } from '@flyxc/optimizer/lib/optimizer'; export interface Request { request: ScoringRequest; diff --git a/libs/optimizer/package.json b/libs/optimizer/package.json index b9e8cdbb..2bd2093c 100644 --- a/libs/optimizer/package.json +++ b/libs/optimizer/package.json @@ -6,7 +6,7 @@ "igc-xc-score": "^1.7.0", "tslib": "^2.3.0" }, - "type": "commonjs", + "type": "module", "main": "./src/index.js", "typings": "./src/index.d.ts" } diff --git a/libs/optimizer/project.json b/libs/optimizer/project.json index 62289a47..ca268d7b 100644 --- a/libs/optimizer/project.json +++ b/libs/optimizer/project.json @@ -9,8 +9,12 @@ "outputs": ["{options.outputPath}"], "options": { "outputPath": "dist/libs/optimizer", - "main": "./src/lib/optimizer.ts", - "additionalEntryPoints": ["libs/optimizer/src/lib/api.ts", "libs/optimizer/src/lib/scoring-rules.ts"], + "main": "libs/optimizer/src/index.ts", + "additionalEntryPoints": [ + "libs/optimizer/src/lib/api.ts", + "libs/optimizer/src/lib/scoring-rules.ts", + "libs/optimizer/src/lib/optimizer.ts" + ], "generateExportsField": true, "tsConfig": "libs/optimizer/tsconfig.lib.json", "assets": ["libs/optimizer/*.md"] diff --git a/libs/optimizer/src/index.ts b/libs/optimizer/src/index.ts new file mode 100644 index 00000000..7496a27e --- /dev/null +++ b/libs/optimizer/src/index.ts @@ -0,0 +1,2 @@ +// Do not export from here as igc-xc-score pollute the global namespace +// See https://github.com/mmomtchev/igc-xc-score/issues/234 diff --git a/libs/optimizer/src/lib/scoring-rules.ts b/libs/optimizer/src/lib/scoring-rules.ts index 1721e78a..eb33d4df 100644 --- a/libs/optimizer/src/lib/scoring-rules.ts +++ b/libs/optimizer/src/lib/scoring-rules.ts @@ -2,7 +2,7 @@ import * as igcXcScore from 'igc-xc-score'; import type { ScoringRuleName } from './api'; // TODO: Export the rules from igc-xc-score -const scoringBaseModel = igcXcScore.scoringRules.XContest; +const scoringBaseModel = igcXcScore.scoringRules['XContest']; const openDistance = scoringBaseModel[0]; const freeTriangle = scoringBaseModel[1]; const faiTriangle = scoringBaseModel[2]; diff --git a/libs/optimizer/tsconfig.json b/libs/optimizer/tsconfig.json index 62ebbd94..a5384dc1 100644 --- a/libs/optimizer/tsconfig.json +++ b/libs/optimizer/tsconfig.json @@ -1,7 +1,16 @@ { "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "ES2022", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, "files": [], - "include": [], + "include": ["src"], "references": [ { "path": "./tsconfig.lib.json" diff --git a/package-lock.json b/package-lock.json index bf524ad1..86eb2834 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,8 +23,8 @@ "@protobuf-ts/runtime": "^2.9.4", "@reduxjs/toolkit": "^2.2.5", "@stencil/core": "^4.18.3", - "@swc-node/register": "1.8.0", - "@swc/core": "^1.3.95", + "@swc-node/register": "~1.9.1", + "@swc/core": "~1.5.7", "@tmcw/togeojson": "^5.8.1", "@types/mapbox__sphericalmercator": "^1.2.3", "@vivaxy/png": "^1.3.0", @@ -86,7 +86,7 @@ "@nx/webpack": "19.1.1", "@nx/workspace": "19.1.1", "@protobuf-ts/plugin": "^2.9.4", - "@swc/helpers": "~0.5.2", + "@swc/helpers": "~0.5.11", "@types/compression": "^1.7.5", "@types/csurf": "^1.11.5", "@types/d3-array": "^3.2.1", @@ -127,6 +127,7 @@ "ts-jest": "^29.1.4", "ts-node": "^10.9.2", "typescript": "5.4.5", + "verdaccio": "^5.0.4", "vite": "~5.0.0", "vite-plugin-checker": "^0.6.4", "vite-plugin-eslint": "^1.8.1", @@ -5149,12 +5150,12 @@ } }, "node_modules/@swc-node/register": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@swc-node/register/-/register-1.8.0.tgz", - "integrity": "sha512-8K3589HoBSmVmrEVrtr4K5sWEithpGDzcFGic81OW0A9sZY38IV5EGRODQWCk0SBDyLhaF+pid120vJAtsHo1A==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@swc-node/register/-/register-1.9.1.tgz", + "integrity": "sha512-z//TBXJdRWXoISCXlQmVz+NMm8Qm/UvcfKiGC0tSJdfeVYf5EZkGqvk2OiRH4SIJ6OGFfS9T0YrvA2pDKzWtPA==", "dependencies": { - "@swc-node/core": "^1.12.0", - "@swc-node/sourcemap-support": "^0.4.0", + "@swc-node/core": "^1.13.1", + "@swc-node/sourcemap-support": "^0.5.0", "colorette": "^2.0.20", "debug": "^4.3.4", "pirates": "^4.0.6", @@ -5165,14 +5166,14 @@ "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "@swc/core": ">= 1.3", + "@swc/core": ">= 1.4.13", "typescript": ">= 4.3" } }, "node_modules/@swc-node/sourcemap-support": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@swc-node/sourcemap-support/-/sourcemap-support-0.4.0.tgz", - "integrity": "sha512-weuRmYTO+4yOtHtPZHXlPdA1dJJJp3QOoZAFZ6uZidu992F2X5v1fQdnb26xs1o3Ex/e2sYhRyY5R6NGNuoATQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@swc-node/sourcemap-support/-/sourcemap-support-0.5.0.tgz", + "integrity": "sha512-fbhjL5G0YvFoWwNhWleuBUfotiX+USiA9oJqu9STFw+Hb0Cgnddn+HVS/K5fI45mn92e8V+cHD2jgFjk4w2T9Q==", "dependencies": { "source-map-support": "^0.5.21", "tslib": "^2.6.2" @@ -5383,7 +5384,7 @@ "version": "0.5.11", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.11.tgz", "integrity": "sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==", - "devOptional": true, + "dev": true, "dependencies": { "tslib": "^2.4.0" } @@ -5689,7 +5690,8 @@ "node_modules/@types/geojson": { "version": "7946.0.14", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==", + "dev": true }, "node_modules/@types/google.maps": { "version": "3.55.9", @@ -5816,6 +5818,12 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==", + "dev": true + }, "node_modules/@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", @@ -6220,205 +6228,1078 @@ "@typescript-eslint/typescript-estree": "7.11.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", + "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.11.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vaadin/a11y-base": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/a11y-base/-/a11y-base-24.3.13.tgz", + "integrity": "sha512-7iEbJiJM/+YIC/D7HzQUuU3OX27MhcNoX8k3mWLBQu8SCVGDerCZUlHCHfeFpbJc76aWDNUrvEhAzBVrM/mn+A==", + "dependencies": { + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/component-base": "~24.3.13", + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/checkbox": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/checkbox/-/checkbox-24.3.13.tgz", + "integrity": "sha512-YT67/M31Dq7UKwtZ+hEUjOrVHnje+7wpf4aBYAeKoEqa57uw2Q9+lGTwoWgviVzXKtXhoQd/oLiNUaxeOVcNzA==", + "dependencies": { + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/a11y-base": "~24.3.13", + "@vaadin/component-base": "~24.3.13", + "@vaadin/field-base": "~24.3.13", + "@vaadin/vaadin-lumo-styles": "~24.3.13", + "@vaadin/vaadin-material-styles": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13", + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/component-base": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/component-base/-/component-base-24.3.13.tgz", + "integrity": "sha512-UjokKlcs3NVnUATmv03Av55dZGCqvRXEaY2N1PO0C5OYATNekF5wlnz2nQ1+j1Tvk9eI+bzZKN28Yu0S3kvl0A==", + "dependencies": { + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-development-mode-detector": "^2.0.0", + "@vaadin/vaadin-usage-statistics": "^2.1.0", + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/field-base": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/field-base/-/field-base-24.3.13.tgz", + "integrity": "sha512-Qc2OUaBDGbskBnnSlDNhQd682tL8QlpqFfoS9lrZhRV286OlkfEiQ06kMZc75Q9fIeVIz3S2BPhtdoxd/8Tc4w==", + "dependencies": { + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/a11y-base": "~24.3.13", + "@vaadin/component-base": "~24.3.13", + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/grid": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/grid/-/grid-24.3.13.tgz", + "integrity": "sha512-oRNP9V6d7khFlB49wDfPfHG1fHFImc9dagX9Tlatpo3j1TLJ9JlfkrdWsuYY1aYtYnx5huvH3iOAV93fV1CFFg==", + "dependencies": { + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/a11y-base": "~24.3.13", + "@vaadin/checkbox": "~24.3.13", + "@vaadin/component-base": "~24.3.13", + "@vaadin/lit-renderer": "~24.3.13", + "@vaadin/text-field": "~24.3.13", + "@vaadin/vaadin-lumo-styles": "~24.3.13", + "@vaadin/vaadin-material-styles": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13" + } + }, + "node_modules/@vaadin/icon": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/icon/-/icon-24.3.13.tgz", + "integrity": "sha512-uH28N3fYJO6FObz+WLNfqHLm2VPbL1hNkmoU/yDiMldfIyTqpbSO2DlwNMXbsm3T8xkJRlHM+LWATheMsIynOw==", + "dependencies": { + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/component-base": "~24.3.13", + "@vaadin/vaadin-lumo-styles": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13", + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/input-container": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/input-container/-/input-container-24.3.13.tgz", + "integrity": "sha512-Rg77JYKwxMdnTqxTIQWkaiNCZGiI4sIP3V6sxYJxqn0v1Nwwy80OQ5nzGQj+KyNk4B6SajmAwgHbu+IcFthN1A==", + "dependencies": { + "@polymer/polymer": "^3.0.0", + "@vaadin/component-base": "~24.3.13", + "@vaadin/vaadin-lumo-styles": "~24.3.13", + "@vaadin/vaadin-material-styles": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13", + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/lit-renderer": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/lit-renderer/-/lit-renderer-24.3.13.tgz", + "integrity": "sha512-5/qtyj6YfdM7BjwH9cpA1y0rPRdKQYr2s6Ze/Ocgfb26DUR6n4daXzilB3TceUanvAFFScGx16CqlA/my1cozQ==", + "dependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/text-field": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/text-field/-/text-field-24.3.13.tgz", + "integrity": "sha512-+f0DGrD+KmVw6s75Gdprugb01LYhsCdLgc2QLTrNjmyx/kvNfw76jTHZEeUuYYjxTMVyKXVstcWxG/oWt/sZSQ==", + "dependencies": { + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/a11y-base": "~24.3.13", + "@vaadin/component-base": "~24.3.13", + "@vaadin/field-base": "~24.3.13", + "@vaadin/input-container": "~24.3.13", + "@vaadin/vaadin-lumo-styles": "~24.3.13", + "@vaadin/vaadin-material-styles": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13", + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/vaadin-development-mode-detector": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-development-mode-detector/-/vaadin-development-mode-detector-2.0.7.tgz", + "integrity": "sha512-9FhVhr0ynSR3X2ao+vaIEttcNU5XfzCbxtmYOV8uIRnUCtNgbvMOIcyGBvntsX9I5kvIP2dV3cFAOG9SILJzEA==" + }, + "node_modules/@vaadin/vaadin-lumo-styles": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-lumo-styles/-/vaadin-lumo-styles-24.3.13.tgz", + "integrity": "sha512-43h6sKTVdNJ2Gv3mTcD1oVHjrNKj28Zs+VqcTUS5Vn2bxmGsIm3V5qLMdSe5GWNeZPbl+5dFa1VjFUjQWElMYw==", + "dependencies": { + "@polymer/polymer": "^3.0.0", + "@vaadin/component-base": "~24.3.13", + "@vaadin/icon": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13" + } + }, + "node_modules/@vaadin/vaadin-material-styles": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-material-styles/-/vaadin-material-styles-24.3.13.tgz", + "integrity": "sha512-TG+y/YPI4M2rXkkyzbb6EzLl2dFaf+sNEH7tZXz4RLAUciKC7QHgpEESwQ0mfdonov2xP9Op48eBhkWalhKxDA==", + "dependencies": { + "@polymer/polymer": "^3.0.0", + "@vaadin/component-base": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13" + } + }, + "node_modules/@vaadin/vaadin-themable-mixin": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-themable-mixin/-/vaadin-themable-mixin-24.3.13.tgz", + "integrity": "sha512-OmDLX92U1tefwgnmlP/OBsf/z/GGjy3IOoEUqEPCgf01+xB6wM6uCRaY1dBU8NgHQeaJq80YzQjP0z5D+SqTkA==", + "dependencies": { + "@open-wc/dedupe-mixin": "^1.3.0", + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/vaadin-usage-statistics": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-usage-statistics/-/vaadin-usage-statistics-2.1.2.tgz", + "integrity": "sha512-xKs1PvRfTXsG0eWWcImLXWjv7D+f1vfoIvovppv6pZ5QX8xgcxWUdNgERlOOdGt3CTuxQXukTBW3+Qfva+OXSg==", + "hasInstallScript": true, + "dependencies": { + "@vaadin/vaadin-development-mode-detector": "^2.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@verdaccio/auth": { + "version": "7.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/auth/-/auth-7.0.0-next-7.15.tgz", + "integrity": "sha512-BWexr0derpjjJh3fNh59aVen5pssvMTLRMTnBi9vmmn1Ndn6cOjeO6a16EhGixFdeef9YFrDMFRY7t96l4QrPQ==", + "dev": true, + "dependencies": { + "@verdaccio/config": "7.0.0-next-7.15", + "@verdaccio/core": "7.0.0-next-7.15", + "@verdaccio/loaders": "7.0.0-next-7.15", + "@verdaccio/logger": "7.0.0-next-7.15", + "@verdaccio/signature": "7.0.0-next-7.5", + "@verdaccio/utils": "7.0.0-next-7.15", + "debug": "4.3.4", + "lodash": "4.17.21", + "verdaccio-htpasswd": "12.0.0-next-7.15" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/auth/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@verdaccio/commons-api": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@verdaccio/commons-api/-/commons-api-10.2.0.tgz", + "integrity": "sha512-F/YZANu4DmpcEV0jronzI7v2fGVWkQ5Mwi+bVmV+ACJ+EzR0c9Jbhtbe5QyLUuzR97t8R5E/Xe53O0cc2LukdQ==", + "dev": true, + "dependencies": { + "http-errors": "2.0.0", + "http-status-codes": "2.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/commons-api/node_modules/http-status-codes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.2.0.tgz", + "integrity": "sha512-feERVo9iWxvnejp3SEfm/+oNG517npqL2/PIA8ORjyOZjGC7TwCRQsZylciLS64i6pJ0wRYz3rkXLRwbtFa8Ng==", + "dev": true + }, + "node_modules/@verdaccio/config": { + "version": "7.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/config/-/config-7.0.0-next-7.15.tgz", + "integrity": "sha512-hXPfDakeyPz2YUo7ORGukKBqOPrNuOpohzWB1GSx6pNDYEepZiRbtpkOTNINiFbFbaXRU42co55PGEsMC3jyPg==", + "dev": true, + "dependencies": { + "@verdaccio/core": "7.0.0-next-7.15", + "@verdaccio/utils": "7.0.0-next-7.15", + "debug": "4.3.4", + "js-yaml": "4.1.0", + "lodash": "4.17.21", + "minimatch": "7.4.6", + "yup": "0.32.11" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/config/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@verdaccio/config/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@verdaccio/config/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@verdaccio/config/node_modules/minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@verdaccio/core": { + "version": "7.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/core/-/core-7.0.0-next-7.15.tgz", + "integrity": "sha512-BsClg5xGXZi755BvzYBrdOQOUNtyXyyslsnehGesy9ryKSRVSpGDi63/bZNHm10hMOkayPH5JE/tjtARX1AfRA==", + "dev": true, + "dependencies": { + "ajv": "8.12.0", + "core-js": "3.35.0", + "http-errors": "2.0.0", + "http-status-codes": "2.3.0", + "process-warning": "1.0.0", + "semver": "7.6.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/core/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@verdaccio/core/node_modules/core-js": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.0.tgz", + "integrity": "sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/@verdaccio/core/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@verdaccio/core/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@verdaccio/core/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@verdaccio/file-locking": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@verdaccio/file-locking/-/file-locking-10.3.1.tgz", + "integrity": "sha512-oqYLfv3Yg3mAgw9qhASBpjD50osj2AX4IwbkUtyuhhKGyoFU9eZdrbeW6tpnqUnj6yBMtAPm2eGD4BwQuX400g==", + "dev": true, + "dependencies": { + "lockfile": "1.0.4" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/loaders": { + "version": "7.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/loaders/-/loaders-7.0.0-next-7.15.tgz", + "integrity": "sha512-X1lgV1DaXkPkEUJzqSZ6ojK4x2TJ+qUkzsyA9s6sBg6MxAe3bCxs9gOytEBA9fPy5f5nTXR63n9+EKaCgOLf2Q==", + "dev": true, + "dependencies": { + "@verdaccio/logger": "7.0.0-next-7.15", + "debug": "4.3.4", + "lodash": "4.17.21" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/loaders/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@verdaccio/local-storage-legacy": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@verdaccio/local-storage-legacy/-/local-storage-legacy-11.0.2.tgz", + "integrity": "sha512-7AXG7qlcVFmF+Nue2oKaraprGRtaBvrQIOvc/E89+7hAe399V01KnZI6E/ET56u7U9fq0MSlp92HBcdotlpUXg==", + "dev": true, + "dependencies": { + "@verdaccio/commons-api": "10.2.0", + "@verdaccio/file-locking": "10.3.1", + "@verdaccio/streams": "10.2.1", + "async": "3.2.4", + "debug": "4.3.4", + "lodash": "4.17.21", + "lowdb": "1.0.0", + "mkdirp": "1.0.4" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/local-storage-legacy/node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "node_modules/@verdaccio/local-storage-legacy/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@verdaccio/local-storage-legacy/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@verdaccio/logger": { + "version": "7.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/logger/-/logger-7.0.0-next-7.15.tgz", + "integrity": "sha512-Ch/dMJ5MV/gw18PFhFMZ0GyvRDzRctlL6XhQpP3p2ZFPiXVAqy/lgRZVQCk8UrKxZYgG6UVXGJMKJT827+esdw==", + "dev": true, + "dependencies": { + "@verdaccio/logger-commons": "7.0.0-next-7.15", + "pino": "8.17.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/logger-7": { + "version": "7.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/logger-7/-/logger-7-7.0.0-next-7.15.tgz", + "integrity": "sha512-yC9WNI9TG5L/Q7J5zoVqRSZoZpbSiib5TL6jztufJ7UFsGz/2TU6f2Vny/w/Mmg6fVl4ddUQeaBnTRV0HDyriQ==", + "dev": true, + "dependencies": { + "@verdaccio/logger-commons": "7.0.0-next-7.15", + "pino": "7.11.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/logger-7/node_modules/on-exit-leak-free": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz", + "integrity": "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==", + "dev": true + }, + "node_modules/@verdaccio/logger-7/node_modules/pino": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-7.11.0.tgz", + "integrity": "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==", + "dev": true, + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.0.0", + "on-exit-leak-free": "^0.2.0", + "pino-abstract-transport": "v0.5.0", + "pino-std-serializers": "^4.0.0", + "process-warning": "^1.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.1.0", + "safe-stable-stringify": "^2.1.0", + "sonic-boom": "^2.2.1", + "thread-stream": "^0.15.1" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/@verdaccio/logger-7/node_modules/pino-abstract-transport": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", + "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", + "dev": true, + "dependencies": { + "duplexify": "^4.1.2", + "split2": "^4.0.0" + } + }, + "node_modules/@verdaccio/logger-7/node_modules/pino-std-serializers": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz", + "integrity": "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==", + "dev": true + }, + "node_modules/@verdaccio/logger-7/node_modules/real-require": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", + "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/@verdaccio/logger-7/node_modules/sonic-boom": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz", + "integrity": "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==", + "dev": true, + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/@verdaccio/logger-7/node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/@verdaccio/logger-7/node_modules/thread-stream": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz", + "integrity": "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==", + "dev": true, + "dependencies": { + "real-require": "^0.1.0" + } + }, + "node_modules/@verdaccio/logger-commons": { + "version": "7.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/logger-commons/-/logger-commons-7.0.0-next-7.15.tgz", + "integrity": "sha512-MeAaU2IMdZSwdO/hrh7aTg1ax3iKlPf6eLVf0JpNYKDxN8OCsi2o5+Q014rGyEG8++Pri3D4DIxMJA7TA+t15g==", + "dev": true, + "dependencies": { + "@verdaccio/core": "7.0.0-next-7.15", + "@verdaccio/logger-prettify": "7.0.0-next-7.2", + "colorette": "2.0.20", + "debug": "4.3.4" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/logger-commons/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@verdaccio/logger-prettify": { + "version": "7.0.0-next-7.2", + "resolved": "https://registry.npmjs.org/@verdaccio/logger-prettify/-/logger-prettify-7.0.0-next-7.2.tgz", + "integrity": "sha512-vGIcXW8DkVBsk0g/iufMZWKBMgC774Vz0zT0g+3NErBUmAhvCby+rrrNDy64jJ8XfJEn+eMiXq7wM/tRWbwYKQ==", + "dev": true, + "dependencies": { + "colorette": "2.0.20", + "dayjs": "1.11.10", + "lodash": "4.17.21", + "pino-abstract-transport": "1.1.0", + "sonic-boom": "3.8.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/middleware": { + "version": "7.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/middleware/-/middleware-7.0.0-next-7.15.tgz", + "integrity": "sha512-54VA3/TbHpb7gIaq3RV9nqR6s4FtuKa5gnpwJEwU/SCdZrZiS2r6+doeQQz96xthrFzpBS1rp0IrRCcRcDs/Uw==", + "dev": true, + "dependencies": { + "@verdaccio/config": "7.0.0-next-7.15", + "@verdaccio/core": "7.0.0-next-7.15", + "@verdaccio/url": "12.0.0-next-7.15", + "@verdaccio/utils": "7.0.0-next-7.15", + "debug": "4.3.4", + "express": "4.18.3", + "express-rate-limit": "5.5.1", + "lodash": "4.17.21", + "lru-cache": "7.18.3", + "mime": "2.6.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/@verdaccio/middleware/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/@verdaccio/middleware/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@verdaccio/middleware/node_modules/express": { + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/@verdaccio/middleware/node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@verdaccio/middleware/node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/@verdaccio/middleware/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@verdaccio/middleware/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@verdaccio/middleware/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@verdaccio/middleware/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/@verdaccio/search-indexer": { + "version": "7.0.0-next-7.2", + "resolved": "https://registry.npmjs.org/@verdaccio/search-indexer/-/search-indexer-7.0.0-next-7.2.tgz", + "integrity": "sha512-ZkhqHHWP530dFr8EuicAa5sXFDlAYqiSgpNDPIyMaz1FkfqngeffhWdydXQgVb60d1OeJkpaf3utPE2kQwIXxQ==", + "dev": true, + "engines": { + "node": ">=12" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" + "url": "https://opencollective.com/verdaccio" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", - "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", + "node_modules/@verdaccio/signature": { + "version": "7.0.0-next-7.5", + "resolved": "https://registry.npmjs.org/@verdaccio/signature/-/signature-7.0.0-next-7.5.tgz", + "integrity": "sha512-xF0xGi10HOAQ7Mkwf6dC2fjaBrdxxqXE/HMh/l/O5/LpWoGFZ6xsm/3ZieVRJtIq/qvL5pmmO5Tn8lPS7pm5SQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", - "eslint-visitor-keys": "^3.4.3" + "debug": "4.3.4", + "jsonwebtoken": "9.0.2" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": ">=14" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/@vaadin/a11y-base": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/a11y-base/-/a11y-base-24.3.13.tgz", - "integrity": "sha512-7iEbJiJM/+YIC/D7HzQUuU3OX27MhcNoX8k3mWLBQu8SCVGDerCZUlHCHfeFpbJc76aWDNUrvEhAzBVrM/mn+A==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.13", - "lit": "^3.0.0" + "url": "https://opencollective.com/verdaccio" } }, - "node_modules/@vaadin/checkbox": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/checkbox/-/checkbox-24.3.13.tgz", - "integrity": "sha512-YT67/M31Dq7UKwtZ+hEUjOrVHnje+7wpf4aBYAeKoEqa57uw2Q9+lGTwoWgviVzXKtXhoQd/oLiNUaxeOVcNzA==", + "node_modules/@verdaccio/signature/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.13", - "@vaadin/component-base": "~24.3.13", - "@vaadin/field-base": "~24.3.13", - "@vaadin/vaadin-lumo-styles": "~24.3.13", - "@vaadin/vaadin-material-styles": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13", - "lit": "^3.0.0" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@vaadin/component-base": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/component-base/-/component-base-24.3.13.tgz", - "integrity": "sha512-UjokKlcs3NVnUATmv03Av55dZGCqvRXEaY2N1PO0C5OYATNekF5wlnz2nQ1+j1Tvk9eI+bzZKN28Yu0S3kvl0A==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/vaadin-development-mode-detector": "^2.0.0", - "@vaadin/vaadin-usage-statistics": "^2.1.0", - "lit": "^3.0.0" + "node_modules/@verdaccio/streams": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/@verdaccio/streams/-/streams-10.2.1.tgz", + "integrity": "sha512-OojIG/f7UYKxC4dYX8x5ax8QhRx1b8OYUAMz82rUottCuzrssX/4nn5QE7Ank0DUSX3C9l/HPthc4d9uKRJqJQ==", + "dev": true, + "engines": { + "node": ">=12", + "npm": ">=5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" } }, - "node_modules/@vaadin/field-base": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/field-base/-/field-base-24.3.13.tgz", - "integrity": "sha512-Qc2OUaBDGbskBnnSlDNhQd682tL8QlpqFfoS9lrZhRV286OlkfEiQ06kMZc75Q9fIeVIz3S2BPhtdoxd/8Tc4w==", + "node_modules/@verdaccio/tarball": { + "version": "12.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/tarball/-/tarball-12.0.0-next-7.15.tgz", + "integrity": "sha512-wjAbLHUxg9FxVmGoW+qvLbv2eWy61MrRkJQWm2+1Zq4JBC6BdKsGZ3AXrpEc+MYi3U1b7Nmi28zXJ9gJ0/HaLQ==", + "dev": true, "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.13", - "@vaadin/component-base": "~24.3.13", - "lit": "^3.0.0" + "@verdaccio/core": "7.0.0-next-7.15", + "@verdaccio/url": "12.0.0-next-7.15", + "@verdaccio/utils": "7.0.0-next-7.15", + "debug": "4.3.4", + "lodash": "4.17.21" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" } }, - "node_modules/@vaadin/grid": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/grid/-/grid-24.3.13.tgz", - "integrity": "sha512-oRNP9V6d7khFlB49wDfPfHG1fHFImc9dagX9Tlatpo3j1TLJ9JlfkrdWsuYY1aYtYnx5huvH3iOAV93fV1CFFg==", + "node_modules/@verdaccio/tarball/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.13", - "@vaadin/checkbox": "~24.3.13", - "@vaadin/component-base": "~24.3.13", - "@vaadin/lit-renderer": "~24.3.13", - "@vaadin/text-field": "~24.3.13", - "@vaadin/vaadin-lumo-styles": "~24.3.13", - "@vaadin/vaadin-material-styles": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@vaadin/icon": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/icon/-/icon-24.3.13.tgz", - "integrity": "sha512-uH28N3fYJO6FObz+WLNfqHLm2VPbL1hNkmoU/yDiMldfIyTqpbSO2DlwNMXbsm3T8xkJRlHM+LWATheMsIynOw==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.13", - "@vaadin/vaadin-lumo-styles": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13", - "lit": "^3.0.0" - } + "node_modules/@verdaccio/ui-theme": { + "version": "7.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/ui-theme/-/ui-theme-7.0.0-next-7.15.tgz", + "integrity": "sha512-4kQr+OKTe+j1ZNBukBsQ4x1GwkM+3qfVuLk0fdGCjPRL+hf6o6piTgIrXsujcJDzSx+lQL6KEqkrmAUsHhjKag==", + "dev": true }, - "node_modules/@vaadin/input-container": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/input-container/-/input-container-24.3.13.tgz", - "integrity": "sha512-Rg77JYKwxMdnTqxTIQWkaiNCZGiI4sIP3V6sxYJxqn0v1Nwwy80OQ5nzGQj+KyNk4B6SajmAwgHbu+IcFthN1A==", + "node_modules/@verdaccio/url": { + "version": "12.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/url/-/url-12.0.0-next-7.15.tgz", + "integrity": "sha512-VyfRKdQv3Urbj8sgUp3xfnm85EHtiTrco1Ve9UbXB0u0SfSpOihUw3TfFzUjLfkyeZE8oBJ8JLZIKmkOm9ZF+w==", + "dev": true, "dependencies": { - "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.13", - "@vaadin/vaadin-lumo-styles": "~24.3.13", - "@vaadin/vaadin-material-styles": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13", - "lit": "^3.0.0" + "@verdaccio/core": "7.0.0-next-7.15", + "debug": "4.3.4", + "lodash": "4.17.21", + "validator": "13.11.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" } }, - "node_modules/@vaadin/lit-renderer": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/lit-renderer/-/lit-renderer-24.3.13.tgz", - "integrity": "sha512-5/qtyj6YfdM7BjwH9cpA1y0rPRdKQYr2s6Ze/Ocgfb26DUR6n4daXzilB3TceUanvAFFScGx16CqlA/my1cozQ==", + "node_modules/@verdaccio/url/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "dependencies": { - "lit": "^3.0.0" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@vaadin/text-field": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/text-field/-/text-field-24.3.13.tgz", - "integrity": "sha512-+f0DGrD+KmVw6s75Gdprugb01LYhsCdLgc2QLTrNjmyx/kvNfw76jTHZEeUuYYjxTMVyKXVstcWxG/oWt/sZSQ==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.13", - "@vaadin/component-base": "~24.3.13", - "@vaadin/field-base": "~24.3.13", - "@vaadin/input-container": "~24.3.13", - "@vaadin/vaadin-lumo-styles": "~24.3.13", - "@vaadin/vaadin-material-styles": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13", - "lit": "^3.0.0" + "node_modules/@verdaccio/url/node_modules/validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", + "dev": true, + "engines": { + "node": ">= 0.10" } }, - "node_modules/@vaadin/vaadin-development-mode-detector": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-development-mode-detector/-/vaadin-development-mode-detector-2.0.7.tgz", - "integrity": "sha512-9FhVhr0ynSR3X2ao+vaIEttcNU5XfzCbxtmYOV8uIRnUCtNgbvMOIcyGBvntsX9I5kvIP2dV3cFAOG9SILJzEA==" - }, - "node_modules/@vaadin/vaadin-lumo-styles": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-lumo-styles/-/vaadin-lumo-styles-24.3.13.tgz", - "integrity": "sha512-43h6sKTVdNJ2Gv3mTcD1oVHjrNKj28Zs+VqcTUS5Vn2bxmGsIm3V5qLMdSe5GWNeZPbl+5dFa1VjFUjQWElMYw==", + "node_modules/@verdaccio/utils": { + "version": "7.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/@verdaccio/utils/-/utils-7.0.0-next-7.15.tgz", + "integrity": "sha512-J0X/SFiCgty5hSI9ghjj4ZG5nf6+txfVWGzuFjlR3UPP1VvpqTu+oya/45sBwZcC/uvfm1LwKCT6tVbcQYlScg==", + "dev": true, "dependencies": { - "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.13", - "@vaadin/icon": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13" + "@verdaccio/core": "7.0.0-next-7.15", + "lodash": "4.17.21", + "minimatch": "7.4.6", + "semver": "7.6.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" } }, - "node_modules/@vaadin/vaadin-material-styles": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-material-styles/-/vaadin-material-styles-24.3.13.tgz", - "integrity": "sha512-TG+y/YPI4M2rXkkyzbb6EzLl2dFaf+sNEH7tZXz4RLAUciKC7QHgpEESwQ0mfdonov2xP9Op48eBhkWalhKxDA==", + "node_modules/@verdaccio/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { - "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@vaadin/vaadin-themable-mixin": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-themable-mixin/-/vaadin-themable-mixin-24.3.13.tgz", - "integrity": "sha512-OmDLX92U1tefwgnmlP/OBsf/z/GGjy3IOoEUqEPCgf01+xB6wM6uCRaY1dBU8NgHQeaJq80YzQjP0z5D+SqTkA==", + "node_modules/@verdaccio/utils/node_modules/minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "lit": "^3.0.0" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@vaadin/vaadin-usage-statistics": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-usage-statistics/-/vaadin-usage-statistics-2.1.2.tgz", - "integrity": "sha512-xKs1PvRfTXsG0eWWcImLXWjv7D+f1vfoIvovppv6pZ5QX8xgcxWUdNgERlOOdGt3CTuxQXukTBW3+Qfva+OXSg==", - "hasInstallScript": true, + "node_modules/@verdaccio/utils/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, "dependencies": { - "@vaadin/vaadin-development-mode-detector": "^2.0.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" } }, + "node_modules/@verdaccio/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@vitejs/plugin-react": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.0.tgz", @@ -7058,6 +7939,15 @@ "node": ">= 8" } }, + "node_modules/apache-md5": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/apache-md5/-/apache-md5-1.1.8.tgz", + "integrity": "sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -7198,6 +8088,15 @@ "node": ">= 4.0.0" } }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/autoprefixer": { "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", @@ -7525,6 +8424,12 @@ "tweetnacl": "^0.14.3" } }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", + "dev": true + }, "node_modules/before-after-hook": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", @@ -8125,8 +9030,23 @@ "engines": { "node": ">=8" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipanion": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/clipanion/-/clipanion-3.2.1.tgz", + "integrity": "sha512-dYFdjLb7y1ajfxQopN05mylEpK9ZX0sO1/RfMXdfmwjlIsPkbh4p7A682x++zFPLDCo1x3p82dtljHf5cW2LKA==", + "dev": true, + "workspaces": [ + "website" + ], + "dependencies": { + "typanion": "^3.8.0" + }, + "peerDependencies": { + "typanion": "*" } }, "node_modules/cliui": { @@ -9449,19 +10369,6 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, "node_modules/dotenv-expand": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", @@ -9666,6 +10573,18 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/errno": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", @@ -10312,6 +11231,12 @@ "node": ">=12.0.0" } }, + "node_modules/express-rate-limit": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.5.1.tgz", + "integrity": "sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==", + "dev": true + }, "node_modules/express-session": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", @@ -10513,6 +11438,21 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, "node_modules/fast-xml-parser": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz", @@ -12028,6 +12968,12 @@ "node": ">=0.10" } }, + "node_modules/http-status-codes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", + "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", + "dev": true + }, "node_modules/https-proxy-agent": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", @@ -12490,6 +13436,12 @@ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -12874,41 +13826,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-circus/node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - } - }, - "node_modules/jest-circus/node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-circus/node_modules/dedent": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", @@ -13920,6 +14837,74 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dev": true, + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dev": true, + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dev": true, + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/jsprim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", @@ -14286,6 +15271,15 @@ "node": ">=8" } }, + "node_modules/lockfile": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", + "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", + "dev": true, + "dependencies": { + "signal-exit": "^3.0.2" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -14313,11 +15307,47 @@ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "dev": true + }, "node_modules/lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "dev": true + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -14438,6 +15468,31 @@ "get-func-name": "^2.0.1" } }, + "node_modules/lowdb": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowdb/-/lowdb-1.0.0.tgz", + "integrity": "sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.3", + "is-promise": "^2.1.0", + "lodash": "4", + "pify": "^3.0.0", + "steno": "^0.4.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lowdb/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/lower-case": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", @@ -14896,6 +15951,78 @@ "multicast-dns": "cli.js" } }, + "node_modules/mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==", + "dev": true, + "dependencies": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/mv/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/mv/node_modules/glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mv/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mv/node_modules/rimraf": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^6.0.1" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/nanoclone": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz", + "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==", + "dev": true + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -14920,6 +16047,15 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==", + "dev": true, + "bin": { + "ncp": "bin/ncp" + } + }, "node_modules/ndjson": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-2.0.0.tgz", @@ -15256,6 +16392,15 @@ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "dev": true }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -15683,6 +16828,99 @@ "node": ">=0.10.0" } }, + "node_modules/pino": { + "version": "8.17.2", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.17.2.tgz", + "integrity": "sha512-LA6qKgeDMLr2ux2y/YiUt47EfgQ+S9LznBWOJdN3q1dx2sv0ziDLUBeVpyVv17TEcGCBuWf0zNtg3M5m1NhhWQ==", + "dev": true, + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "v1.1.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^3.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.7.0", + "thread-stream": "^2.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.1.0.tgz", + "integrity": "sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==", + "dev": true, + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-abstract-transport/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "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" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/pino-abstract-transport/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/pino-abstract-transport/node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/pino-std-serializers": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==", + "dev": true + }, + "node_modules/pino/node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "dev": true + }, "node_modules/pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", @@ -15799,6 +17037,15 @@ "pathe": "^1.1.2" } }, + "node_modules/pkginfo": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz", + "integrity": "sha512-8xCNE/aT/EXKenuMDZ+xTVwkT8gsoHN2z/Q29l80u0ppGEXVvsKRzNMbtKhg8LS8k1tJLAHHylf6p4VFmP6XUQ==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/platform": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", @@ -16506,6 +17753,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/process-warning": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", + "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==", + "dev": true + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -16528,6 +17781,12 @@ "node": "*" } }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", + "dev": true + }, "node_modules/proto3-json-serializer": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz", @@ -16758,6 +18017,12 @@ } ] }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "dev": true + }, "node_modules/quickselect": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", @@ -16867,6 +18132,15 @@ "node": ">=8.10.0" } }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", @@ -17332,6 +18606,15 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -17819,6 +19102,15 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/sonic-boom": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.0.tgz", + "integrity": "sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==", + "dev": true, + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, "node_modules/sortablejs": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.2.tgz", @@ -18014,6 +19306,15 @@ "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", "dev": true }, + "node_modules/steno": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/steno/-/steno-0.4.4.tgz", + "integrity": "sha512-EEHMVYHNXFHfGtgjNITnka0aHhiAlo93F7z2/Pwd+g0teG9CnM3JIINM7hVVB5/rhw9voufD7Wukwgtw2uqh6w==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.3" + } + }, "node_modules/stream-events": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", @@ -18752,6 +20053,15 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/thread-stream": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", + "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", + "dev": true, + "dependencies": { + "real-require": "^0.2.0" + } + }, "node_modules/throttleit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", @@ -18872,6 +20182,12 @@ "node": ">=0.6" } }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", + "dev": true + }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", @@ -19123,6 +20439,15 @@ "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, + "node_modules/typanion": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/typanion/-/typanion-3.14.0.tgz", + "integrity": "sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==", + "dev": true, + "workspaces": [ + "website" + ] + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -19182,6 +20507,7 @@ "version": "5.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -19309,6 +20635,12 @@ "node": ">= 10.0.0" } }, + "node_modules/unix-crypt-td-js": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/unix-crypt-td-js/-/unix-crypt-td-js-1.1.4.tgz", + "integrity": "sha512-8rMeVYWSIyccIJscb9NdCfZKSRBKYTeVnwmiRYT2ulE3qd1RaDQ0xQDP+rI3ccIWbhu/zuo5cgN8z73belNZgw==", + "dev": true + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -19470,6 +20802,320 @@ "node": ">= 0.8" } }, + "node_modules/verdaccio": { + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/verdaccio/-/verdaccio-5.31.0.tgz", + "integrity": "sha512-jqBUlvFVArgv5AwtrwUQHDEI9rJHbr8YhA+Wzl56hBZ3Egso9dG9XUiDV+Pbl0yjf7CFghKKuWtQ2Bo6neZXqw==", + "dev": true, + "dependencies": { + "@cypress/request": "3.0.1", + "@verdaccio/auth": "7.0.0-next-7.15", + "@verdaccio/config": "7.0.0-next-7.15", + "@verdaccio/core": "7.0.0-next-7.15", + "@verdaccio/local-storage-legacy": "11.0.2", + "@verdaccio/logger-7": "7.0.0-next-7.15", + "@verdaccio/middleware": "7.0.0-next-7.15", + "@verdaccio/search-indexer": "7.0.0-next-7.2", + "@verdaccio/signature": "7.0.0-next-7.5", + "@verdaccio/streams": "10.2.1", + "@verdaccio/tarball": "12.0.0-next-7.15", + "@verdaccio/ui-theme": "7.0.0-next-7.15", + "@verdaccio/url": "12.0.0-next-7.15", + "@verdaccio/utils": "7.0.0-next-7.15", + "async": "3.2.5", + "clipanion": "3.2.1", + "compression": "1.7.4", + "cors": "2.8.5", + "debug": "^4.3.4", + "envinfo": "7.13.0", + "express": "4.19.2", + "express-rate-limit": "5.5.1", + "fast-safe-stringify": "2.1.1", + "handlebars": "4.7.8", + "js-yaml": "4.1.0", + "JSONStream": "1.3.5", + "jsonwebtoken": "9.0.2", + "kleur": "4.1.5", + "lodash": "4.17.21", + "lru-cache": "7.18.3", + "mime": "3.0.0", + "mkdirp": "1.0.4", + "mv": "2.1.1", + "pkginfo": "0.4.1", + "semver": "7.6.2", + "validator": "13.12.0", + "verdaccio-audit": "12.0.0-next-7.15", + "verdaccio-htpasswd": "12.0.0-next-7.15" + }, + "bin": { + "verdaccio": "bin/verdaccio" + }, + "engines": { + "node": ">=12.18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/verdaccio-audit": { + "version": "12.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/verdaccio-audit/-/verdaccio-audit-12.0.0-next-7.15.tgz", + "integrity": "sha512-ylUxj3VZljYyCpAUFa3THFb29UyHCVv8qgte0LI/20+5EptcZuayHtVP5sd5mnMiMqCO4TUylm30EdXSIvqk4A==", + "dev": true, + "dependencies": { + "@verdaccio/config": "7.0.0-next-7.15", + "@verdaccio/core": "7.0.0-next-7.15", + "express": "4.18.3", + "https-proxy-agent": "5.0.1", + "node-fetch": "cjs" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/verdaccio-audit/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/verdaccio-audit/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/verdaccio-audit/node_modules/express": { + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/verdaccio-audit/node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/verdaccio-audit/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/verdaccio-audit/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/verdaccio-audit/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/verdaccio-audit/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/verdaccio-htpasswd": { + "version": "12.0.0-next-7.15", + "resolved": "https://registry.npmjs.org/verdaccio-htpasswd/-/verdaccio-htpasswd-12.0.0-next-7.15.tgz", + "integrity": "sha512-m8yXFdYi8FQfP9VeZA3Rdecgkn3QWeeMVEV7bA49w0rpC2DBgOfUcKGNMfZZL4C4gv8M3spCZgJH2adKEFbfbw==", + "dev": true, + "dependencies": { + "@verdaccio/core": "7.0.0-next-7.15", + "@verdaccio/file-locking": "12.0.0-next.1", + "apache-md5": "1.1.8", + "bcryptjs": "2.4.3", + "core-js": "3.35.0", + "debug": "4.3.4", + "http-errors": "2.0.0", + "unix-crypt-td-js": "1.1.4" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/verdaccio-htpasswd/node_modules/@verdaccio/file-locking": { + "version": "12.0.0-next.1", + "resolved": "https://registry.npmjs.org/@verdaccio/file-locking/-/file-locking-12.0.0-next.1.tgz", + "integrity": "sha512-Zb5G2HEhVRB0jCq4z7QA4dqTdRv/2kIsw2Nkm3j2HqC1OeJRxas3MJAF/OxzbAb1IN32lbg1zycMSk6NcbQkgQ==", + "dev": true, + "dependencies": { + "lockfile": "1.0.4" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/verdaccio" + } + }, + "node_modules/verdaccio-htpasswd/node_modules/core-js": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.0.tgz", + "integrity": "sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/verdaccio-htpasswd/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/verdaccio/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/verdaccio/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/verdaccio/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/verdaccio/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/verdaccio/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -20701,6 +22347,24 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/yup": { + "version": "0.32.11", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz", + "integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/lodash": "^4.14.175", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "nanoclone": "^0.2.1", + "property-expr": "^2.0.4", + "toposort": "^2.0.2" + }, + "engines": { + "node": ">=10" + } } } } From a4d458fc044a6ddb8f0e973e567564aaf26baac5 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Tue, 4 Jun 2024 10:38:19 +0200 Subject: [PATCH 20/20] deps --- package-lock.json | 2597 +++++++++++---------------------------------- package.json | 6 +- 2 files changed, 633 insertions(+), 1970 deletions(-) diff --git a/package-lock.json b/package-lock.json index 86eb2834..8a739d2c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,7 +72,7 @@ }, "devDependencies": { "@esri/arcgis-rest-geocoding": "^4.0.2", - "@esri/arcgis-rest-request": "^4.2.1", + "@esri/arcgis-rest-request": "^4.2.2", "@nx-tools/nx-container": "^6.0.1", "@nx/cypress": "19.1.1", "@nx/eslint": "19.1.1", @@ -86,7 +86,7 @@ "@nx/webpack": "19.1.1", "@nx/workspace": "19.1.1", "@protobuf-ts/plugin": "^2.9.4", - "@swc/helpers": "~0.5.11", + "@swc/helpers": "~0.5.2", "@types/compression": "^1.7.5", "@types/csurf": "^1.11.5", "@types/d3-array": "^3.2.1", @@ -127,7 +127,6 @@ "ts-jest": "^29.1.4", "ts-node": "^10.9.2", "typescript": "5.4.5", - "verdaccio": "^5.0.4", "vite": "~5.0.0", "vite-plugin-checker": "^0.6.4", "vite-plugin-eslint": "^1.8.1", @@ -2722,9 +2721,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -2895,9 +2894,9 @@ } }, "node_modules/@esri/arcgis-rest-request": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@esri/arcgis-rest-request/-/arcgis-rest-request-4.2.1.tgz", - "integrity": "sha512-MK8ZrKqJuPDhYDxm9kcDYDtGfWVIMn8ldw6xHthvPhp/6/ZbZZ9B5MwL92Nmdyl2Q1hngiXxCbetW62uLUHj9g==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@esri/arcgis-rest-request/-/arcgis-rest-request-4.2.2.tgz", + "integrity": "sha512-SWcNhzhW6+bmDgkeTFVC9zgnPSqXSOueX5hVxWZztV2xM1Ag/B6kSBDoP92lRXJ6kcDT8JuNs4wXxUKZfonXNg==", "dev": true, "dependencies": { "@esri/arcgis-rest-fetch": "^4.0.0", @@ -3767,12 +3766,13 @@ } }, "node_modules/@nrwl/devkit": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", - "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", + "version": "19.1.2", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.2.tgz", + "integrity": "sha512-vWI+OrTICE9Yw6C/jIwxybnvavI9dnQJ7tpzFbLcSVfFAGdFtYJGCLVe40IkWcvUfELoVmzpXtKP/sPy0D7J9w==", "dev": true, + "peer": true, "dependencies": { - "@nx/devkit": "19.1.1" + "@nx/devkit": "19.1.2" } }, "node_modules/@nrwl/eslint-plugin-nx": { @@ -3963,7 +3963,16 @@ } } }, - "node_modules/@nx/devkit": { + "node_modules/@nx/cypress/node_modules/@nrwl/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.1.1" + } + }, + "node_modules/@nx/cypress/node_modules/@nx/devkit": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", @@ -3983,6 +3992,27 @@ "nx": ">= 17 <= 20" } }, + "node_modules/@nx/devkit": { + "version": "19.1.2", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.2.tgz", + "integrity": "sha512-oHYZzfmvogPh7z8pf1RjW7eJaS05VZ1Ts/axlWerzQauWT7aoeyCaxa0D9q3ThnUuDt1PqKjwJi5jmCihBT2Sw==", + "dev": true, + "peer": true, + "dependencies": { + "@nrwl/devkit": "19.1.2", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@nx/eslint": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/@nx/eslint/-/eslint-19.1.1.tgz", @@ -4033,6 +4063,64 @@ } } }, + "node_modules/@nx/eslint-plugin/node_modules/@nrwl/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.1.1" + } + }, + "node_modules/@nx/eslint-plugin/node_modules/@nx/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.1.1", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, + "node_modules/@nx/eslint/node_modules/@nrwl/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.1.1" + } + }, + "node_modules/@nx/eslint/node_modules/@nx/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.1.1", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@nx/express": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/@nx/express/-/express-19.1.1.tgz", @@ -4053,6 +4141,35 @@ } } }, + "node_modules/@nx/express/node_modules/@nrwl/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.1.1" + } + }, + "node_modules/@nx/express/node_modules/@nx/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.1.1", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@nx/jest": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/@nx/jest/-/jest-19.1.1.tgz", @@ -4076,6 +4193,35 @@ "yargs-parser": "21.1.1" } }, + "node_modules/@nx/jest/node_modules/@nrwl/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.1.1" + } + }, + "node_modules/@nx/jest/node_modules/@nx/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.1.1", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@nx/js": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/@nx/js/-/js-19.1.1.tgz", @@ -4121,6 +4267,35 @@ } } }, + "node_modules/@nx/js/node_modules/@nrwl/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.1.1" + } + }, + "node_modules/@nx/js/node_modules/@nx/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.1.1", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@nx/js/node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -4187,6 +4362,35 @@ "tslib": "^2.3.0" } }, + "node_modules/@nx/node/node_modules/@nrwl/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.1.1" + } + }, + "node_modules/@nx/node/node_modules/@nx/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.1.1", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@nx/nx-darwin-arm64": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.1.1.tgz", @@ -4366,6 +4570,35 @@ "vitest": "^1.3.1" } }, + "node_modules/@nx/vite/node_modules/@nrwl/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.1.1" + } + }, + "node_modules/@nx/vite/node_modules/@nx/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.1.1", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@nx/web": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/@nx/web/-/web-19.1.1.tgz", @@ -4381,6 +4614,35 @@ "tslib": "^2.3.0" } }, + "node_modules/@nx/web/node_modules/@nrwl/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.1.1" + } + }, + "node_modules/@nx/web/node_modules/@nx/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.1.1", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@nx/webpack": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/@nx/webpack/-/webpack-19.1.1.tgz", @@ -4426,21 +4688,79 @@ "webpack-subresource-integrity": "^5.1.0" } }, - "node_modules/@nx/workspace": { + "node_modules/@nx/webpack/node_modules/@nrwl/devkit": { "version": "19.1.1", - "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-19.1.1.tgz", - "integrity": "sha512-aTOAGotI8tbQiYp1jx+n0+SK18fpmPeRNA95y7xH8uMZLcm7zfOZiE0r450nbAVwU62JWncCvxwdB2weBVkY4w==", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", "dev": true, "dependencies": { - "@nrwl/workspace": "19.1.1", - "@nx/devkit": "19.1.1", - "chalk": "^4.1.0", - "enquirer": "~2.3.6", + "@nx/devkit": "19.1.1" + } + }, + "node_modules/@nx/webpack/node_modules/@nx/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.1.1", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, + "node_modules/@nx/workspace": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-19.1.1.tgz", + "integrity": "sha512-aTOAGotI8tbQiYp1jx+n0+SK18fpmPeRNA95y7xH8uMZLcm7zfOZiE0r450nbAVwU62JWncCvxwdB2weBVkY4w==", + "dev": true, + "dependencies": { + "@nrwl/workspace": "19.1.1", + "@nx/devkit": "19.1.1", + "chalk": "^4.1.0", + "enquirer": "~2.3.6", "nx": "19.1.1", "tslib": "^2.3.0", "yargs-parser": "21.1.1" } }, + "node_modules/@nx/workspace/node_modules/@nrwl/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-CrbEy4zBRPPV8gGtwpSgfxJUElXRxEGvvxQlrhoCKmzH7v9407jFjXpzYOipwa9u65a7raCCtsSKYuRdecRglQ==", + "dev": true, + "dependencies": { + "@nx/devkit": "19.1.1" + } + }, + "node_modules/@nx/workspace/node_modules/@nx/devkit": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.1.tgz", + "integrity": "sha512-YMt5vFaNMeIKgBwQ3RIFQG7AoYOksd8vNxwunirN95q/70HMIoJQsnRCMT45jVd9D/GIWASgY8QsGTMJfcO0qQ==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "19.1.1", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 17 <= 20" + } + }, "node_modules/@octokit/auth-token": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", @@ -5384,7 +5704,7 @@ "version": "0.5.11", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.11.tgz", "integrity": "sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==", - "dev": true, + "devOptional": true, "dependencies": { "tslib": "^2.4.0" } @@ -5690,8 +6010,7 @@ "node_modules/@types/geojson": { "version": "7946.0.14", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==", - "dev": true + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" }, "node_modules/@types/google.maps": { "version": "3.55.9", @@ -5818,12 +6137,6 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, - "node_modules/@types/lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==", - "dev": true - }, "node_modules/@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", @@ -6056,16 +6369,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz", - "integrity": "sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz", + "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.11.0", - "@typescript-eslint/type-utils": "7.11.0", - "@typescript-eslint/utils": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/type-utils": "7.12.0", + "@typescript-eslint/utils": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -6089,15 +6402,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz", - "integrity": "sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", + "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.11.0", - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/typescript-estree": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "debug": "^4.3.4" }, "engines": { @@ -6117,13 +6430,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz", - "integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz", + "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0" + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6134,13 +6447,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz", - "integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz", + "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.11.0", - "@typescript-eslint/utils": "7.11.0", + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/utils": "7.12.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -6161,9 +6474,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", - "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz", + "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6174,13 +6487,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", - "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz", + "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6191,1115 +6504,242 @@ "engines": { "node": "^18.18.0 || >=20.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz", - "integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.11.0", - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/typescript-estree": "7.11.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", - "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.11.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/@vaadin/a11y-base": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/a11y-base/-/a11y-base-24.3.13.tgz", - "integrity": "sha512-7iEbJiJM/+YIC/D7HzQUuU3OX27MhcNoX8k3mWLBQu8SCVGDerCZUlHCHfeFpbJc76aWDNUrvEhAzBVrM/mn+A==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.13", - "lit": "^3.0.0" - } - }, - "node_modules/@vaadin/checkbox": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/checkbox/-/checkbox-24.3.13.tgz", - "integrity": "sha512-YT67/M31Dq7UKwtZ+hEUjOrVHnje+7wpf4aBYAeKoEqa57uw2Q9+lGTwoWgviVzXKtXhoQd/oLiNUaxeOVcNzA==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.13", - "@vaadin/component-base": "~24.3.13", - "@vaadin/field-base": "~24.3.13", - "@vaadin/vaadin-lumo-styles": "~24.3.13", - "@vaadin/vaadin-material-styles": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13", - "lit": "^3.0.0" - } - }, - "node_modules/@vaadin/component-base": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/component-base/-/component-base-24.3.13.tgz", - "integrity": "sha512-UjokKlcs3NVnUATmv03Av55dZGCqvRXEaY2N1PO0C5OYATNekF5wlnz2nQ1+j1Tvk9eI+bzZKN28Yu0S3kvl0A==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/vaadin-development-mode-detector": "^2.0.0", - "@vaadin/vaadin-usage-statistics": "^2.1.0", - "lit": "^3.0.0" - } - }, - "node_modules/@vaadin/field-base": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/field-base/-/field-base-24.3.13.tgz", - "integrity": "sha512-Qc2OUaBDGbskBnnSlDNhQd682tL8QlpqFfoS9lrZhRV286OlkfEiQ06kMZc75Q9fIeVIz3S2BPhtdoxd/8Tc4w==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.13", - "@vaadin/component-base": "~24.3.13", - "lit": "^3.0.0" - } - }, - "node_modules/@vaadin/grid": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/grid/-/grid-24.3.13.tgz", - "integrity": "sha512-oRNP9V6d7khFlB49wDfPfHG1fHFImc9dagX9Tlatpo3j1TLJ9JlfkrdWsuYY1aYtYnx5huvH3iOAV93fV1CFFg==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.13", - "@vaadin/checkbox": "~24.3.13", - "@vaadin/component-base": "~24.3.13", - "@vaadin/lit-renderer": "~24.3.13", - "@vaadin/text-field": "~24.3.13", - "@vaadin/vaadin-lumo-styles": "~24.3.13", - "@vaadin/vaadin-material-styles": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13" - } - }, - "node_modules/@vaadin/icon": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/icon/-/icon-24.3.13.tgz", - "integrity": "sha512-uH28N3fYJO6FObz+WLNfqHLm2VPbL1hNkmoU/yDiMldfIyTqpbSO2DlwNMXbsm3T8xkJRlHM+LWATheMsIynOw==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.13", - "@vaadin/vaadin-lumo-styles": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13", - "lit": "^3.0.0" - } - }, - "node_modules/@vaadin/input-container": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/input-container/-/input-container-24.3.13.tgz", - "integrity": "sha512-Rg77JYKwxMdnTqxTIQWkaiNCZGiI4sIP3V6sxYJxqn0v1Nwwy80OQ5nzGQj+KyNk4B6SajmAwgHbu+IcFthN1A==", - "dependencies": { - "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.13", - "@vaadin/vaadin-lumo-styles": "~24.3.13", - "@vaadin/vaadin-material-styles": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13", - "lit": "^3.0.0" - } - }, - "node_modules/@vaadin/lit-renderer": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/lit-renderer/-/lit-renderer-24.3.13.tgz", - "integrity": "sha512-5/qtyj6YfdM7BjwH9cpA1y0rPRdKQYr2s6Ze/Ocgfb26DUR6n4daXzilB3TceUanvAFFScGx16CqlA/my1cozQ==", - "dependencies": { - "lit": "^3.0.0" - } - }, - "node_modules/@vaadin/text-field": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/text-field/-/text-field-24.3.13.tgz", - "integrity": "sha512-+f0DGrD+KmVw6s75Gdprugb01LYhsCdLgc2QLTrNjmyx/kvNfw76jTHZEeUuYYjxTMVyKXVstcWxG/oWt/sZSQ==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.13", - "@vaadin/component-base": "~24.3.13", - "@vaadin/field-base": "~24.3.13", - "@vaadin/input-container": "~24.3.13", - "@vaadin/vaadin-lumo-styles": "~24.3.13", - "@vaadin/vaadin-material-styles": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13", - "lit": "^3.0.0" - } - }, - "node_modules/@vaadin/vaadin-development-mode-detector": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-development-mode-detector/-/vaadin-development-mode-detector-2.0.7.tgz", - "integrity": "sha512-9FhVhr0ynSR3X2ao+vaIEttcNU5XfzCbxtmYOV8uIRnUCtNgbvMOIcyGBvntsX9I5kvIP2dV3cFAOG9SILJzEA==" - }, - "node_modules/@vaadin/vaadin-lumo-styles": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-lumo-styles/-/vaadin-lumo-styles-24.3.13.tgz", - "integrity": "sha512-43h6sKTVdNJ2Gv3mTcD1oVHjrNKj28Zs+VqcTUS5Vn2bxmGsIm3V5qLMdSe5GWNeZPbl+5dFa1VjFUjQWElMYw==", - "dependencies": { - "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.13", - "@vaadin/icon": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13" - } - }, - "node_modules/@vaadin/vaadin-material-styles": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-material-styles/-/vaadin-material-styles-24.3.13.tgz", - "integrity": "sha512-TG+y/YPI4M2rXkkyzbb6EzLl2dFaf+sNEH7tZXz4RLAUciKC7QHgpEESwQ0mfdonov2xP9Op48eBhkWalhKxDA==", - "dependencies": { - "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.13", - "@vaadin/vaadin-themable-mixin": "~24.3.13" - } - }, - "node_modules/@vaadin/vaadin-themable-mixin": { - "version": "24.3.13", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-themable-mixin/-/vaadin-themable-mixin-24.3.13.tgz", - "integrity": "sha512-OmDLX92U1tefwgnmlP/OBsf/z/GGjy3IOoEUqEPCgf01+xB6wM6uCRaY1dBU8NgHQeaJq80YzQjP0z5D+SqTkA==", - "dependencies": { - "@open-wc/dedupe-mixin": "^1.3.0", - "lit": "^3.0.0" - } - }, - "node_modules/@vaadin/vaadin-usage-statistics": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-usage-statistics/-/vaadin-usage-statistics-2.1.2.tgz", - "integrity": "sha512-xKs1PvRfTXsG0eWWcImLXWjv7D+f1vfoIvovppv6pZ5QX8xgcxWUdNgERlOOdGt3CTuxQXukTBW3+Qfva+OXSg==", - "hasInstallScript": true, - "dependencies": { - "@vaadin/vaadin-development-mode-detector": "^2.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/@verdaccio/auth": { - "version": "7.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/auth/-/auth-7.0.0-next-7.15.tgz", - "integrity": "sha512-BWexr0derpjjJh3fNh59aVen5pssvMTLRMTnBi9vmmn1Ndn6cOjeO6a16EhGixFdeef9YFrDMFRY7t96l4QrPQ==", - "dev": true, - "dependencies": { - "@verdaccio/config": "7.0.0-next-7.15", - "@verdaccio/core": "7.0.0-next-7.15", - "@verdaccio/loaders": "7.0.0-next-7.15", - "@verdaccio/logger": "7.0.0-next-7.15", - "@verdaccio/signature": "7.0.0-next-7.5", - "@verdaccio/utils": "7.0.0-next-7.15", - "debug": "4.3.4", - "lodash": "4.17.21", - "verdaccio-htpasswd": "12.0.0-next-7.15" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/auth/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@verdaccio/commons-api": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@verdaccio/commons-api/-/commons-api-10.2.0.tgz", - "integrity": "sha512-F/YZANu4DmpcEV0jronzI7v2fGVWkQ5Mwi+bVmV+ACJ+EzR0c9Jbhtbe5QyLUuzR97t8R5E/Xe53O0cc2LukdQ==", - "dev": true, - "dependencies": { - "http-errors": "2.0.0", - "http-status-codes": "2.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/commons-api/node_modules/http-status-codes": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.2.0.tgz", - "integrity": "sha512-feERVo9iWxvnejp3SEfm/+oNG517npqL2/PIA8ORjyOZjGC7TwCRQsZylciLS64i6pJ0wRYz3rkXLRwbtFa8Ng==", - "dev": true - }, - "node_modules/@verdaccio/config": { - "version": "7.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/config/-/config-7.0.0-next-7.15.tgz", - "integrity": "sha512-hXPfDakeyPz2YUo7ORGukKBqOPrNuOpohzWB1GSx6pNDYEepZiRbtpkOTNINiFbFbaXRU42co55PGEsMC3jyPg==", - "dev": true, - "dependencies": { - "@verdaccio/core": "7.0.0-next-7.15", - "@verdaccio/utils": "7.0.0-next-7.15", - "debug": "4.3.4", - "js-yaml": "4.1.0", - "lodash": "4.17.21", - "minimatch": "7.4.6", - "yup": "0.32.11" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/config/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@verdaccio/config/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@verdaccio/config/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@verdaccio/config/node_modules/minimatch": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", - "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@verdaccio/core": { - "version": "7.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/core/-/core-7.0.0-next-7.15.tgz", - "integrity": "sha512-BsClg5xGXZi755BvzYBrdOQOUNtyXyyslsnehGesy9ryKSRVSpGDi63/bZNHm10hMOkayPH5JE/tjtARX1AfRA==", - "dev": true, - "dependencies": { - "ajv": "8.12.0", - "core-js": "3.35.0", - "http-errors": "2.0.0", - "http-status-codes": "2.3.0", - "process-warning": "1.0.0", - "semver": "7.6.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/core/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@verdaccio/core/node_modules/core-js": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.0.tgz", - "integrity": "sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg==", - "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/@verdaccio/core/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@verdaccio/core/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@verdaccio/core/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@verdaccio/file-locking": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@verdaccio/file-locking/-/file-locking-10.3.1.tgz", - "integrity": "sha512-oqYLfv3Yg3mAgw9qhASBpjD50osj2AX4IwbkUtyuhhKGyoFU9eZdrbeW6tpnqUnj6yBMtAPm2eGD4BwQuX400g==", - "dev": true, - "dependencies": { - "lockfile": "1.0.4" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/loaders": { - "version": "7.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/loaders/-/loaders-7.0.0-next-7.15.tgz", - "integrity": "sha512-X1lgV1DaXkPkEUJzqSZ6ojK4x2TJ+qUkzsyA9s6sBg6MxAe3bCxs9gOytEBA9fPy5f5nTXR63n9+EKaCgOLf2Q==", - "dev": true, - "dependencies": { - "@verdaccio/logger": "7.0.0-next-7.15", - "debug": "4.3.4", - "lodash": "4.17.21" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/loaders/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@verdaccio/local-storage-legacy": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@verdaccio/local-storage-legacy/-/local-storage-legacy-11.0.2.tgz", - "integrity": "sha512-7AXG7qlcVFmF+Nue2oKaraprGRtaBvrQIOvc/E89+7hAe399V01KnZI6E/ET56u7U9fq0MSlp92HBcdotlpUXg==", - "dev": true, - "dependencies": { - "@verdaccio/commons-api": "10.2.0", - "@verdaccio/file-locking": "10.3.1", - "@verdaccio/streams": "10.2.1", - "async": "3.2.4", - "debug": "4.3.4", - "lodash": "4.17.21", - "lowdb": "1.0.0", - "mkdirp": "1.0.4" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/local-storage-legacy/node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, - "node_modules/@verdaccio/local-storage-legacy/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@verdaccio/local-storage-legacy/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@verdaccio/logger": { - "version": "7.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/logger/-/logger-7.0.0-next-7.15.tgz", - "integrity": "sha512-Ch/dMJ5MV/gw18PFhFMZ0GyvRDzRctlL6XhQpP3p2ZFPiXVAqy/lgRZVQCk8UrKxZYgG6UVXGJMKJT827+esdw==", - "dev": true, - "dependencies": { - "@verdaccio/logger-commons": "7.0.0-next-7.15", - "pino": "8.17.2" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/logger-7": { - "version": "7.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/logger-7/-/logger-7-7.0.0-next-7.15.tgz", - "integrity": "sha512-yC9WNI9TG5L/Q7J5zoVqRSZoZpbSiib5TL6jztufJ7UFsGz/2TU6f2Vny/w/Mmg6fVl4ddUQeaBnTRV0HDyriQ==", - "dev": true, - "dependencies": { - "@verdaccio/logger-commons": "7.0.0-next-7.15", - "pino": "7.11.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/logger-7/node_modules/on-exit-leak-free": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz", - "integrity": "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==", - "dev": true - }, - "node_modules/@verdaccio/logger-7/node_modules/pino": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-7.11.0.tgz", - "integrity": "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==", - "dev": true, - "dependencies": { - "atomic-sleep": "^1.0.0", - "fast-redact": "^3.0.0", - "on-exit-leak-free": "^0.2.0", - "pino-abstract-transport": "v0.5.0", - "pino-std-serializers": "^4.0.0", - "process-warning": "^1.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.1.0", - "safe-stable-stringify": "^2.1.0", - "sonic-boom": "^2.2.1", - "thread-stream": "^0.15.1" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/@verdaccio/logger-7/node_modules/pino-abstract-transport": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", - "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", - "dev": true, - "dependencies": { - "duplexify": "^4.1.2", - "split2": "^4.0.0" - } - }, - "node_modules/@verdaccio/logger-7/node_modules/pino-std-serializers": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz", - "integrity": "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==", - "dev": true - }, - "node_modules/@verdaccio/logger-7/node_modules/real-require": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", - "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/@verdaccio/logger-7/node_modules/sonic-boom": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz", - "integrity": "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==", - "dev": true, - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, - "node_modules/@verdaccio/logger-7/node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/@verdaccio/logger-7/node_modules/thread-stream": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz", - "integrity": "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==", - "dev": true, - "dependencies": { - "real-require": "^0.1.0" - } - }, - "node_modules/@verdaccio/logger-commons": { - "version": "7.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/logger-commons/-/logger-commons-7.0.0-next-7.15.tgz", - "integrity": "sha512-MeAaU2IMdZSwdO/hrh7aTg1ax3iKlPf6eLVf0JpNYKDxN8OCsi2o5+Q014rGyEG8++Pri3D4DIxMJA7TA+t15g==", - "dev": true, - "dependencies": { - "@verdaccio/core": "7.0.0-next-7.15", - "@verdaccio/logger-prettify": "7.0.0-next-7.2", - "colorette": "2.0.20", - "debug": "4.3.4" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/logger-commons/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@verdaccio/logger-prettify": { - "version": "7.0.0-next-7.2", - "resolved": "https://registry.npmjs.org/@verdaccio/logger-prettify/-/logger-prettify-7.0.0-next-7.2.tgz", - "integrity": "sha512-vGIcXW8DkVBsk0g/iufMZWKBMgC774Vz0zT0g+3NErBUmAhvCby+rrrNDy64jJ8XfJEn+eMiXq7wM/tRWbwYKQ==", - "dev": true, - "dependencies": { - "colorette": "2.0.20", - "dayjs": "1.11.10", - "lodash": "4.17.21", - "pino-abstract-transport": "1.1.0", - "sonic-boom": "3.8.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/middleware": { - "version": "7.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/middleware/-/middleware-7.0.0-next-7.15.tgz", - "integrity": "sha512-54VA3/TbHpb7gIaq3RV9nqR6s4FtuKa5gnpwJEwU/SCdZrZiS2r6+doeQQz96xthrFzpBS1rp0IrRCcRcDs/Uw==", - "dev": true, - "dependencies": { - "@verdaccio/config": "7.0.0-next-7.15", - "@verdaccio/core": "7.0.0-next-7.15", - "@verdaccio/url": "12.0.0-next-7.15", - "@verdaccio/utils": "7.0.0-next-7.15", - "debug": "4.3.4", - "express": "4.18.3", - "express-rate-limit": "5.5.1", - "lodash": "4.17.21", - "lru-cache": "7.18.3", - "mime": "2.6.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/middleware/node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true - }, - "node_modules/@verdaccio/middleware/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@verdaccio/middleware/node_modules/express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/@verdaccio/middleware/node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/@verdaccio/middleware/node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/@verdaccio/middleware/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@verdaccio/middleware/node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/@verdaccio/middleware/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@verdaccio/middleware/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/@verdaccio/search-indexer": { - "version": "7.0.0-next-7.2", - "resolved": "https://registry.npmjs.org/@verdaccio/search-indexer/-/search-indexer-7.0.0-next-7.2.tgz", - "integrity": "sha512-ZkhqHHWP530dFr8EuicAa5sXFDlAYqiSgpNDPIyMaz1FkfqngeffhWdydXQgVb60d1OeJkpaf3utPE2kQwIXxQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/signature": { - "version": "7.0.0-next-7.5", - "resolved": "https://registry.npmjs.org/@verdaccio/signature/-/signature-7.0.0-next-7.5.tgz", - "integrity": "sha512-xF0xGi10HOAQ7Mkwf6dC2fjaBrdxxqXE/HMh/l/O5/LpWoGFZ6xsm/3ZieVRJtIq/qvL5pmmO5Tn8lPS7pm5SQ==", - "dev": true, - "dependencies": { - "debug": "4.3.4", - "jsonwebtoken": "9.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/@verdaccio/signature/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependenciesMeta": { - "supports-color": { + "typescript": { "optional": true } } }, - "node_modules/@verdaccio/streams": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/@verdaccio/streams/-/streams-10.2.1.tgz", - "integrity": "sha512-OojIG/f7UYKxC4dYX8x5ax8QhRx1b8OYUAMz82rUottCuzrssX/4nn5QE7Ank0DUSX3C9l/HPthc4d9uKRJqJQ==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, "engines": { - "node": ">=12", - "npm": ">=5" + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@verdaccio/tarball": { - "version": "12.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/tarball/-/tarball-12.0.0-next-7.15.tgz", - "integrity": "sha512-wjAbLHUxg9FxVmGoW+qvLbv2eWy61MrRkJQWm2+1Zq4JBC6BdKsGZ3AXrpEc+MYi3U1b7Nmi28zXJ9gJ0/HaLQ==", + "node_modules/@typescript-eslint/utils": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz", + "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==", "dev": true, "dependencies": { - "@verdaccio/core": "7.0.0-next-7.15", - "@verdaccio/url": "12.0.0-next-7.15", - "@verdaccio/utils": "7.0.0-next-7.15", - "debug": "4.3.4", - "lodash": "4.17.21" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0" }, "engines": { - "node": ">=12" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/verdaccio" + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" } }, - "node_modules/@verdaccio/tarball/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz", + "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==", "dev": true, "dependencies": { - "ms": "2.1.2" + "@typescript-eslint/types": "7.12.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=6.0" + "node": "^18.18.0 || >=20.0.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@verdaccio/ui-theme": { - "version": "7.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/ui-theme/-/ui-theme-7.0.0-next-7.15.tgz", - "integrity": "sha512-4kQr+OKTe+j1ZNBukBsQ4x1GwkM+3qfVuLk0fdGCjPRL+hf6o6piTgIrXsujcJDzSx+lQL6KEqkrmAUsHhjKag==", + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, - "node_modules/@verdaccio/url": { - "version": "12.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/url/-/url-12.0.0-next-7.15.tgz", - "integrity": "sha512-VyfRKdQv3Urbj8sgUp3xfnm85EHtiTrco1Ve9UbXB0u0SfSpOihUw3TfFzUjLfkyeZE8oBJ8JLZIKmkOm9ZF+w==", - "dev": true, + "node_modules/@vaadin/a11y-base": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/a11y-base/-/a11y-base-24.3.13.tgz", + "integrity": "sha512-7iEbJiJM/+YIC/D7HzQUuU3OX27MhcNoX8k3mWLBQu8SCVGDerCZUlHCHfeFpbJc76aWDNUrvEhAzBVrM/mn+A==", "dependencies": { - "@verdaccio/core": "7.0.0-next-7.15", - "debug": "4.3.4", - "lodash": "4.17.21", - "validator": "13.11.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/component-base": "~24.3.13", + "lit": "^3.0.0" } }, - "node_modules/@verdaccio/url/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, + "node_modules/@vaadin/checkbox": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/checkbox/-/checkbox-24.3.13.tgz", + "integrity": "sha512-YT67/M31Dq7UKwtZ+hEUjOrVHnje+7wpf4aBYAeKoEqa57uw2Q9+lGTwoWgviVzXKtXhoQd/oLiNUaxeOVcNzA==", "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/a11y-base": "~24.3.13", + "@vaadin/component-base": "~24.3.13", + "@vaadin/field-base": "~24.3.13", + "@vaadin/vaadin-lumo-styles": "~24.3.13", + "@vaadin/vaadin-material-styles": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13", + "lit": "^3.0.0" } }, - "node_modules/@verdaccio/url/node_modules/validator": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", - "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", - "dev": true, - "engines": { - "node": ">= 0.10" + "node_modules/@vaadin/component-base": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/component-base/-/component-base-24.3.13.tgz", + "integrity": "sha512-UjokKlcs3NVnUATmv03Av55dZGCqvRXEaY2N1PO0C5OYATNekF5wlnz2nQ1+j1Tvk9eI+bzZKN28Yu0S3kvl0A==", + "dependencies": { + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-development-mode-detector": "^2.0.0", + "@vaadin/vaadin-usage-statistics": "^2.1.0", + "lit": "^3.0.0" } }, - "node_modules/@verdaccio/utils": { - "version": "7.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/@verdaccio/utils/-/utils-7.0.0-next-7.15.tgz", - "integrity": "sha512-J0X/SFiCgty5hSI9ghjj4ZG5nf6+txfVWGzuFjlR3UPP1VvpqTu+oya/45sBwZcC/uvfm1LwKCT6tVbcQYlScg==", - "dev": true, + "node_modules/@vaadin/field-base": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/field-base/-/field-base-24.3.13.tgz", + "integrity": "sha512-Qc2OUaBDGbskBnnSlDNhQd682tL8QlpqFfoS9lrZhRV286OlkfEiQ06kMZc75Q9fIeVIz3S2BPhtdoxd/8Tc4w==", "dependencies": { - "@verdaccio/core": "7.0.0-next-7.15", - "lodash": "4.17.21", - "minimatch": "7.4.6", - "semver": "7.6.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/a11y-base": "~24.3.13", + "@vaadin/component-base": "~24.3.13", + "lit": "^3.0.0" } }, - "node_modules/@verdaccio/utils/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, + "node_modules/@vaadin/grid": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/grid/-/grid-24.3.13.tgz", + "integrity": "sha512-oRNP9V6d7khFlB49wDfPfHG1fHFImc9dagX9Tlatpo3j1TLJ9JlfkrdWsuYY1aYtYnx5huvH3iOAV93fV1CFFg==", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/a11y-base": "~24.3.13", + "@vaadin/checkbox": "~24.3.13", + "@vaadin/component-base": "~24.3.13", + "@vaadin/lit-renderer": "~24.3.13", + "@vaadin/text-field": "~24.3.13", + "@vaadin/vaadin-lumo-styles": "~24.3.13", + "@vaadin/vaadin-material-styles": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13" } }, - "node_modules/@verdaccio/utils/node_modules/minimatch": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", - "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", - "dev": true, + "node_modules/@vaadin/icon": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/icon/-/icon-24.3.13.tgz", + "integrity": "sha512-uH28N3fYJO6FObz+WLNfqHLm2VPbL1hNkmoU/yDiMldfIyTqpbSO2DlwNMXbsm3T8xkJRlHM+LWATheMsIynOw==", "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/component-base": "~24.3.13", + "@vaadin/vaadin-lumo-styles": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13", + "lit": "^3.0.0" } }, - "node_modules/@verdaccio/utils/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, + "node_modules/@vaadin/input-container": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/input-container/-/input-container-24.3.13.tgz", + "integrity": "sha512-Rg77JYKwxMdnTqxTIQWkaiNCZGiI4sIP3V6sxYJxqn0v1Nwwy80OQ5nzGQj+KyNk4B6SajmAwgHbu+IcFthN1A==", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@polymer/polymer": "^3.0.0", + "@vaadin/component-base": "~24.3.13", + "@vaadin/vaadin-lumo-styles": "~24.3.13", + "@vaadin/vaadin-material-styles": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13", + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/lit-renderer": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/lit-renderer/-/lit-renderer-24.3.13.tgz", + "integrity": "sha512-5/qtyj6YfdM7BjwH9cpA1y0rPRdKQYr2s6Ze/Ocgfb26DUR6n4daXzilB3TceUanvAFFScGx16CqlA/my1cozQ==", + "dependencies": { + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/text-field": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/text-field/-/text-field-24.3.13.tgz", + "integrity": "sha512-+f0DGrD+KmVw6s75Gdprugb01LYhsCdLgc2QLTrNjmyx/kvNfw76jTHZEeUuYYjxTMVyKXVstcWxG/oWt/sZSQ==", + "dependencies": { + "@open-wc/dedupe-mixin": "^1.3.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/a11y-base": "~24.3.13", + "@vaadin/component-base": "~24.3.13", + "@vaadin/field-base": "~24.3.13", + "@vaadin/input-container": "~24.3.13", + "@vaadin/vaadin-lumo-styles": "~24.3.13", + "@vaadin/vaadin-material-styles": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13", + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/vaadin-development-mode-detector": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-development-mode-detector/-/vaadin-development-mode-detector-2.0.7.tgz", + "integrity": "sha512-9FhVhr0ynSR3X2ao+vaIEttcNU5XfzCbxtmYOV8uIRnUCtNgbvMOIcyGBvntsX9I5kvIP2dV3cFAOG9SILJzEA==" + }, + "node_modules/@vaadin/vaadin-lumo-styles": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-lumo-styles/-/vaadin-lumo-styles-24.3.13.tgz", + "integrity": "sha512-43h6sKTVdNJ2Gv3mTcD1oVHjrNKj28Zs+VqcTUS5Vn2bxmGsIm3V5qLMdSe5GWNeZPbl+5dFa1VjFUjQWElMYw==", + "dependencies": { + "@polymer/polymer": "^3.0.0", + "@vaadin/component-base": "~24.3.13", + "@vaadin/icon": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13" + } + }, + "node_modules/@vaadin/vaadin-material-styles": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-material-styles/-/vaadin-material-styles-24.3.13.tgz", + "integrity": "sha512-TG+y/YPI4M2rXkkyzbb6EzLl2dFaf+sNEH7tZXz4RLAUciKC7QHgpEESwQ0mfdonov2xP9Op48eBhkWalhKxDA==", + "dependencies": { + "@polymer/polymer": "^3.0.0", + "@vaadin/component-base": "~24.3.13", + "@vaadin/vaadin-themable-mixin": "~24.3.13" + } + }, + "node_modules/@vaadin/vaadin-themable-mixin": { + "version": "24.3.13", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-themable-mixin/-/vaadin-themable-mixin-24.3.13.tgz", + "integrity": "sha512-OmDLX92U1tefwgnmlP/OBsf/z/GGjy3IOoEUqEPCgf01+xB6wM6uCRaY1dBU8NgHQeaJq80YzQjP0z5D+SqTkA==", + "dependencies": { + "@open-wc/dedupe-mixin": "^1.3.0", + "lit": "^3.0.0" + } + }, + "node_modules/@vaadin/vaadin-usage-statistics": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-usage-statistics/-/vaadin-usage-statistics-2.1.2.tgz", + "integrity": "sha512-xKs1PvRfTXsG0eWWcImLXWjv7D+f1vfoIvovppv6pZ5QX8xgcxWUdNgERlOOdGt3CTuxQXukTBW3+Qfva+OXSg==", + "hasInstallScript": true, + "dependencies": { + "@vaadin/vaadin-development-mode-detector": "^2.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/@verdaccio/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@vitejs/plugin-react": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.0.tgz", @@ -7812,15 +7252,15 @@ } }, "node_modules/ajv": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.14.0.tgz", - "integrity": "sha512-oYs1UUtO97ZO2lJ4bwnWeQW8/zvOIQLGKcvPTsWmvc2SYgBb+upuNS5NxoLaMU4h8Ju3Nbj6Cq8mD2LQoqVKFA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.15.0.tgz", + "integrity": "sha512-15BTtQUOsSrmHCy+B4VnAiJAJxJ8IFgu6fcjFQF3jQYZ78nLSQthlFg4ehp+NLIyfvFgOlxNsjKIEhydtFPVHQ==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^2.3.0", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -7939,15 +7379,6 @@ "node": ">= 8" } }, - "node_modules/apache-md5": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/apache-md5/-/apache-md5-1.1.8.tgz", - "integrity": "sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -8088,15 +7519,6 @@ "node": ">= 4.0.0" } }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/autoprefixer": { "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", @@ -8424,12 +7846,6 @@ "tweetnacl": "^0.14.3" } }, - "node_modules/bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", - "dev": true - }, "node_modules/before-after-hook": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", @@ -8803,9 +8219,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001625", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001625.tgz", - "integrity": "sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w==", + "version": "1.0.30001627", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001627.tgz", + "integrity": "sha512-4zgNiB8nTyV/tHhwZrFs88ryjls/lHiqFhrxCW4qSTeuRByBVnPYpDInchOIySWknznucaf31Z4KYqjfbrecVw==", "dev": true, "funding": [ { @@ -9034,21 +8450,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/clipanion": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/clipanion/-/clipanion-3.2.1.tgz", - "integrity": "sha512-dYFdjLb7y1ajfxQopN05mylEpK9ZX0sO1/RfMXdfmwjlIsPkbh4p7A682x++zFPLDCo1x3p82dtljHf5cW2LKA==", - "dev": true, - "workspaces": [ - "website" - ], - "dependencies": { - "typanion": "^3.8.0" - }, - "peerDependencies": { - "typanion": "*" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -10366,7 +9767,20 @@ "domhandler": "^5.0.3" }, "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" } }, "node_modules/dotenv-expand": { @@ -10469,9 +9883,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.788", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.788.tgz", - "integrity": "sha512-ubp5+Ev/VV8KuRoWnfP2QF2Bg+O2ZFdb49DiiNbz2VmgkIqrnyYaqIOqj8A6K/3p1xV0QcU5hBQ1+BmB6ot1OA==", + "version": "1.4.789", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.789.tgz", + "integrity": "sha512-0VbyiaXoT++Fi2vHGo2ThOeS6X3vgRCWrjPeO2FeIAWL6ItiSJ9BqlH8LfCXe3X1IdcG+S0iLoNaxQWhfZoGzQ==", "dev": true }, "node_modules/elliptic": { @@ -10573,18 +9987,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/errno": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", @@ -11231,12 +10633,6 @@ "node": ">=12.0.0" } }, - "node_modules/express-rate-limit": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.5.1.tgz", - "integrity": "sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==", - "dev": true - }, "node_modules/express-session": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", @@ -11438,19 +10834,10 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, - "node_modules/fast-redact": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", - "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "node_modules/fast-uri": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.3.0.tgz", + "integrity": "sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==", "dev": true }, "node_modules/fast-xml-parser": { @@ -12968,12 +12355,6 @@ "node": ">=0.10" } }, - "node_modules/http-status-codes": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", - "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", - "dev": true - }, "node_modules/https-proxy-agent": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", @@ -13436,12 +12817,6 @@ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -13638,9 +13013,9 @@ } }, "node_modules/jackspeak": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", - "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.2.3.tgz", + "integrity": "sha512-htOzIMPbpLid/Gq9/zaz9SfExABxqRe1sSCdxntlO/aMD6u0issZQiY25n2GKQUtJ02j7z5sfptlAOMpWWOmvw==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -13826,6 +13201,41 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-circus/node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/jest-circus/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jest-circus/node_modules/dedent": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", @@ -14837,74 +14247,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", - "dev": true, - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/jsonwebtoken/node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dev": true, - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jsonwebtoken/node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dev": true, - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/jsprim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", @@ -15271,15 +14613,6 @@ "node": ">=8" } }, - "node_modules/lockfile": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", - "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", - "dev": true, - "dependencies": { - "signal-exit": "^3.0.2" - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -15307,47 +14640,11 @@ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", - "dev": true - }, "node_modules/lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "dev": true - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", - "dev": true - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", - "dev": true - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "dev": true - }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -15468,31 +14765,6 @@ "get-func-name": "^2.0.1" } }, - "node_modules/lowdb": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowdb/-/lowdb-1.0.0.tgz", - "integrity": "sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.3", - "is-promise": "^2.1.0", - "lodash": "4", - "pify": "^3.0.0", - "steno": "^0.4.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lowdb/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/lower-case": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", @@ -15951,78 +15223,6 @@ "multicast-dns": "cli.js" } }, - "node_modules/mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==", - "dev": true, - "dependencies": { - "mkdirp": "~0.5.1", - "ncp": "~2.0.0", - "rimraf": "~2.4.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/mv/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/mv/node_modules/glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mv/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mv/node_modules/rimraf": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^6.0.1" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/nanoclone": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz", - "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==", - "dev": true - }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -16047,15 +15247,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==", - "dev": true, - "bin": { - "ncp": "bin/ncp" - } - }, "node_modules/ndjson": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-2.0.0.tgz", @@ -16392,15 +15583,6 @@ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "dev": true }, - "node_modules/on-exit-leak-free": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -16828,99 +16010,6 @@ "node": ">=0.10.0" } }, - "node_modules/pino": { - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/pino/-/pino-8.17.2.tgz", - "integrity": "sha512-LA6qKgeDMLr2ux2y/YiUt47EfgQ+S9LznBWOJdN3q1dx2sv0ziDLUBeVpyVv17TEcGCBuWf0zNtg3M5m1NhhWQ==", - "dev": true, - "dependencies": { - "atomic-sleep": "^1.0.0", - "fast-redact": "^3.1.1", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "v1.1.0", - "pino-std-serializers": "^6.0.0", - "process-warning": "^3.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^3.7.0", - "thread-stream": "^2.0.0" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/pino-abstract-transport": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.1.0.tgz", - "integrity": "sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==", - "dev": true, - "dependencies": { - "readable-stream": "^4.0.0", - "split2": "^4.0.0" - } - }, - "node_modules/pino-abstract-transport/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "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" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/pino-abstract-transport/node_modules/readable-stream": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", - "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", - "dev": true, - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/pino-abstract-transport/node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/pino-std-serializers": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", - "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==", - "dev": true - }, - "node_modules/pino/node_modules/process-warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", - "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", - "dev": true - }, "node_modules/pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", @@ -17037,15 +16126,6 @@ "pathe": "^1.1.2" } }, - "node_modules/pkginfo": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz", - "integrity": "sha512-8xCNE/aT/EXKenuMDZ+xTVwkT8gsoHN2z/Q29l80u0ppGEXVvsKRzNMbtKhg8LS8k1tJLAHHylf6p4VFmP6XUQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/platform": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", @@ -17753,12 +16833,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "node_modules/process-warning": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", - "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==", - "dev": true - }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -17779,13 +16853,7 @@ "dev": true, "engines": { "node": "*" - } - }, - "node_modules/property-expr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", - "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", - "dev": true + } }, "node_modules/proto3-json-serializer": { "version": "2.0.2", @@ -18017,12 +17085,6 @@ } ] }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", - "dev": true - }, "node_modules/quickselect": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", @@ -18132,15 +17194,6 @@ "node": ">=8.10.0" } }, - "node_modules/real-require": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - } - }, "node_modules/redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", @@ -18320,9 +17373,9 @@ "dev": true }, "node_modules/reselect": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz", - "integrity": "sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg==" + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" }, "node_modules/resolve": { "version": "1.22.8", @@ -18606,15 +17659,6 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -19102,15 +18146,6 @@ "websocket-driver": "^0.7.4" } }, - "node_modules/sonic-boom": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.0.tgz", - "integrity": "sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==", - "dev": true, - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, "node_modules/sortablejs": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.2.tgz", @@ -19306,15 +18341,6 @@ "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", "dev": true }, - "node_modules/steno": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/steno/-/steno-0.4.4.tgz", - "integrity": "sha512-EEHMVYHNXFHfGtgjNITnka0aHhiAlo93F7z2/Pwd+g0teG9CnM3JIINM7hVVB5/rhw9voufD7Wukwgtw2uqh6w==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.3" - } - }, "node_modules/stream-events": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", @@ -20053,15 +19079,6 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/thread-stream": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", - "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", - "dev": true, - "dependencies": { - "real-require": "^0.2.0" - } - }, "node_modules/throttleit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", @@ -20182,12 +19199,6 @@ "node": ">=0.6" } }, - "node_modules/toposort": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", - "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", - "dev": true - }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", @@ -20439,15 +19450,6 @@ "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, - "node_modules/typanion": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/typanion/-/typanion-3.14.0.tgz", - "integrity": "sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==", - "dev": true, - "workspaces": [ - "website" - ] - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -20507,7 +19509,6 @@ "version": "5.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -20635,12 +19636,6 @@ "node": ">= 10.0.0" } }, - "node_modules/unix-crypt-td-js": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/unix-crypt-td-js/-/unix-crypt-td-js-1.1.4.tgz", - "integrity": "sha512-8rMeVYWSIyccIJscb9NdCfZKSRBKYTeVnwmiRYT2ulE3qd1RaDQ0xQDP+rI3ccIWbhu/zuo5cgN8z73belNZgw==", - "dev": true - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -20802,320 +19797,6 @@ "node": ">= 0.8" } }, - "node_modules/verdaccio": { - "version": "5.31.0", - "resolved": "https://registry.npmjs.org/verdaccio/-/verdaccio-5.31.0.tgz", - "integrity": "sha512-jqBUlvFVArgv5AwtrwUQHDEI9rJHbr8YhA+Wzl56hBZ3Egso9dG9XUiDV+Pbl0yjf7CFghKKuWtQ2Bo6neZXqw==", - "dev": true, - "dependencies": { - "@cypress/request": "3.0.1", - "@verdaccio/auth": "7.0.0-next-7.15", - "@verdaccio/config": "7.0.0-next-7.15", - "@verdaccio/core": "7.0.0-next-7.15", - "@verdaccio/local-storage-legacy": "11.0.2", - "@verdaccio/logger-7": "7.0.0-next-7.15", - "@verdaccio/middleware": "7.0.0-next-7.15", - "@verdaccio/search-indexer": "7.0.0-next-7.2", - "@verdaccio/signature": "7.0.0-next-7.5", - "@verdaccio/streams": "10.2.1", - "@verdaccio/tarball": "12.0.0-next-7.15", - "@verdaccio/ui-theme": "7.0.0-next-7.15", - "@verdaccio/url": "12.0.0-next-7.15", - "@verdaccio/utils": "7.0.0-next-7.15", - "async": "3.2.5", - "clipanion": "3.2.1", - "compression": "1.7.4", - "cors": "2.8.5", - "debug": "^4.3.4", - "envinfo": "7.13.0", - "express": "4.19.2", - "express-rate-limit": "5.5.1", - "fast-safe-stringify": "2.1.1", - "handlebars": "4.7.8", - "js-yaml": "4.1.0", - "JSONStream": "1.3.5", - "jsonwebtoken": "9.0.2", - "kleur": "4.1.5", - "lodash": "4.17.21", - "lru-cache": "7.18.3", - "mime": "3.0.0", - "mkdirp": "1.0.4", - "mv": "2.1.1", - "pkginfo": "0.4.1", - "semver": "7.6.2", - "validator": "13.12.0", - "verdaccio-audit": "12.0.0-next-7.15", - "verdaccio-htpasswd": "12.0.0-next-7.15" - }, - "bin": { - "verdaccio": "bin/verdaccio" - }, - "engines": { - "node": ">=12.18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/verdaccio-audit": { - "version": "12.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/verdaccio-audit/-/verdaccio-audit-12.0.0-next-7.15.tgz", - "integrity": "sha512-ylUxj3VZljYyCpAUFa3THFb29UyHCVv8qgte0LI/20+5EptcZuayHtVP5sd5mnMiMqCO4TUylm30EdXSIvqk4A==", - "dev": true, - "dependencies": { - "@verdaccio/config": "7.0.0-next-7.15", - "@verdaccio/core": "7.0.0-next-7.15", - "express": "4.18.3", - "https-proxy-agent": "5.0.1", - "node-fetch": "cjs" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/verdaccio-audit/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/verdaccio-audit/node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true - }, - "node_modules/verdaccio-audit/node_modules/express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/verdaccio-audit/node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/verdaccio-audit/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/verdaccio-audit/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/verdaccio-audit/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/verdaccio-audit/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/verdaccio-htpasswd": { - "version": "12.0.0-next-7.15", - "resolved": "https://registry.npmjs.org/verdaccio-htpasswd/-/verdaccio-htpasswd-12.0.0-next-7.15.tgz", - "integrity": "sha512-m8yXFdYi8FQfP9VeZA3Rdecgkn3QWeeMVEV7bA49w0rpC2DBgOfUcKGNMfZZL4C4gv8M3spCZgJH2adKEFbfbw==", - "dev": true, - "dependencies": { - "@verdaccio/core": "7.0.0-next-7.15", - "@verdaccio/file-locking": "12.0.0-next.1", - "apache-md5": "1.1.8", - "bcryptjs": "2.4.3", - "core-js": "3.35.0", - "debug": "4.3.4", - "http-errors": "2.0.0", - "unix-crypt-td-js": "1.1.4" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/verdaccio-htpasswd/node_modules/@verdaccio/file-locking": { - "version": "12.0.0-next.1", - "resolved": "https://registry.npmjs.org/@verdaccio/file-locking/-/file-locking-12.0.0-next.1.tgz", - "integrity": "sha512-Zb5G2HEhVRB0jCq4z7QA4dqTdRv/2kIsw2Nkm3j2HqC1OeJRxas3MJAF/OxzbAb1IN32lbg1zycMSk6NcbQkgQ==", - "dev": true, - "dependencies": { - "lockfile": "1.0.4" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/verdaccio" - } - }, - "node_modules/verdaccio-htpasswd/node_modules/core-js": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.0.tgz", - "integrity": "sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg==", - "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/verdaccio-htpasswd/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/verdaccio/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/verdaccio/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/verdaccio/node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/verdaccio/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/verdaccio/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -22347,24 +21028,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/yup": { - "version": "0.32.11", - "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz", - "integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.15.4", - "@types/lodash": "^4.14.175", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "nanoclone": "^0.2.1", - "property-expr": "^2.0.4", - "toposort": "^2.0.2" - }, - "engines": { - "node": ">=10" - } } } } diff --git a/package.json b/package.json index 3f213d7e..f9da67a9 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "private": true, "devDependencies": { "@esri/arcgis-rest-geocoding": "^4.0.2", - "@esri/arcgis-rest-request": "^4.2.1", + "@esri/arcgis-rest-request": "^4.2.2", "@nx-tools/nx-container": "^6.0.1", "@nx/cypress": "19.1.1", "@nx/eslint": "19.1.1", @@ -92,8 +92,8 @@ "@protobuf-ts/runtime": "^2.9.4", "@reduxjs/toolkit": "^2.2.5", "@stencil/core": "^4.18.3", - "@swc-node/register": "1.8.0", - "@swc/core": "^1.3.95", + "@swc-node/register": "~1.9.1", + "@swc/core": "~1.5.7", "@tmcw/togeojson": "^5.8.1", "@types/mapbox__sphericalmercator": "^1.2.3", "@vivaxy/png": "^1.3.0",